#java #class #interface #solid-principles #single-responsibility-principle
#java #класс #интерфейс #solid-принципы #принцип единой ответственности
Вопрос:
У меня есть некоторый код, который я хотел бы переработать, чтобы он не нарушал принцип единой ответственности (SRP).
Я понимаю, что приведенный ниже класс может измениться по нескольким причинам:
- Бизнес-правила для анализа могут измениться
- Схема метаданных может измениться
- Метод загрузки может измениться
Тем не менее, мне трудно понять, как я могу разделить отдельные классы.
Engine.java
package com.example;
import java.util.List;
public interface Engine {
public List<Recording> analyze(List<String> files);
public List<Recording> getMetadata(List<Recording> recordings);
public List<Recording> upload(List<Recording> recordings);
}
CallEngine.java
package com.example;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CallEngine implements Engine {
final static Logger log = LoggerFactory.getLogger(Main.class);
public List<Recording> analyze(List<String> files) {
log.info("Analyzing recording files per business rules...");
List<Recording> recordings = new ArrayList<Recording>();
return recordings;
}
public List<Recording> getMetadata(List<Recording> r) {
log.info("Retrieving metadata for calls...");
List<Recording> recordings = new ArrayList<Recording>();
return recordings;
}
public List<Recording> upload(List<Recording> r) {
log.info("Uploading calls...");
List<Recording> recordings = new ArrayList<Recording>();
return recordings;
}
}
Ответ №1:
SRP в первую очередь достигается за счет абстрагирования кода за интерфейсами и делегирования ответственности за несвязанную функциональность той реализации, которая оказывается за интерфейсом во время выполнения.
В этом случае вам нужно абстрагировать обязанности за их собственным интерфейсом.
Например…
public interface Analyzer {
public List<Recording> analyze(List<String> files);
}
public interface Retriever {
public List<Recording> getMetadata(List<Recording> recordings);
}
public interface Uploader {
public List<Recording> upload(List<Recording> r);
}
И иметь их в качестве встроенных зависимостей Engine
реализации.
public class CallEngine implements Engine {
private Analyzer analyzer;
private Retriever retriever;
private Uploader uploader;
public CallEngine(Analyzer analyzer, Retriever retriever, Uploader uploader) {
this.analyzer = analyzer;
this.retriever = retriever;
this.uploader = uploader;
}
public List<Recording> analyze(List<String> files) {
return analyzer.analyze(files);
}
public List<Recording> getMetadata(List<Recording> r) {
return retriever.getMetadata(r);
}
public List<Recording> upload(List<Recording> r) {
return uploader.upload(r);
}
}
Их реализации во время выполнения могут быть изменены, не влияя на общую ответственность реализации зависимого класса, что делает его гораздо более адаптивным к изменениям.
Ответ №2:
public interface Analyzer {
public void analyze();
}
public interface Retriever {
public void retrieveMetadata();
}
public interface Uploader {
public void upload();
}
public class EngineAnalyzer implements Analyzer {
final static Logger log = LoggerFactory.getLogger(Main.class);
public List<Recording> recordings;
EngineAnaylzer(List<String> Files) {
}
public void analyze() {
log.info("Analyzing recording files per business rules...");
}
}