Итак, если мы говорим об общих указателях, то для начала есть несколько простых вещей.
- ваш класс
Chunk
должен заниматься только своей основной обязанностью — управлять всем, что содержится в классе Chunk
.
- похоже, вам нужен
ChunkGroup
, потенциально используя шаблон адаптера на фрагменте, который объединяет «сеть» из Chunk
.
- должны существовать некоторые средства сохранения объектов
Chunk
. Это не входит в обязанности самого Chunk
, но может включать внутренний класс, который позволяет преобразовывать Chunk
во что-то, что можно (де)сериализовать.
Итак, я ожидал увидеть что-то вроде
interface Chunk {
String doTheThing();
}
interface ChunkNetwork extends Chunk {
add(Chunk chunk);
};
final class ChunkList implements ChunkNetwork {
private List<Chunk> theChunks;
add(Chunk chunk) {
theChunks.add(chunk);
}
String doTheThing() {
StringBuilder builder = new StringBuilder();
for (Chunk chunk : theChunks) {
builder.append(chunk.doTheThing());
}
return builder.toString();
}
}
final class JsonChunk implements Chunk {
@JsonProperty
private final int someField;
@Override
public String doTheThing() {
String.format("%d", someField);
}
@JsonCreator
public JsonChunk(int fieldValue) {
someField = fieldValue;
}
}
Что следует отметить в отношении SRP здесь:
- Интерфейс Chunk содержит только методы, относящиеся к основной функциональности, которую должен выполнять Chunk.
- адаптер извлекает функциональность для создания «сети» объектов
Chunk
в отдельный класс. Существуют разные способы управления такими сетями, вы можете изменить их позже. Вы можете сделать это, не изменяя принцип работы самого Chunk
.
ChunkNetwork
может иметь разные методы в зависимости от вашего использования, и это может сообщить вам, как вы решите реализовать интерфейс, но ключевым моментом является то, что управление сетью находится за пределами самого Chunk
.
- то, как объекты
Chunk
представлены в XML или JSON (или что-то еще, на диске, в файле), является отдельной проблемой от того, что такое API Chunk
. Однако с такими библиотеками, как Jackson, мы часто можем обойтись без определения отдельного класса для маршалинга/демаршаллинга. Однако, если ваши реализации Chunk
станут сложными, вы можете захотеть это сделать.
В конечном счете, SRP говорит, что у любого отдельного класса должна быть одна причина для изменения. Поэтому вам нужно посмотреть на свою функциональность и понять, почему она может измениться. Типичные причины:
- изменения в основной функциональности. Для вашего домена могут потребоваться дополнительные/измененные функции. Это было бы эквивалентно изменению интерфейса
Chunk
.
- изменения в том, как устроены основные объекты, чтобы обеспечить представление высокого уровня в системе (возможно, вы решите представить сеть из
Chunk
с использованием древовидной структуры). Эквивалентно изменению (или повторной реализации) класса ChunkList
.
- изменения в том, как происходит настойчивость. Это может быть изменение аннотаций, которые используют библиотеки сохранения (например, Jackson, JPA, JAXB и т. д.), или это может быть совершенно новая структура класса, представляющая «Объект передачи данных».
Как правило, если вы обнаружите, что описываете класс, используя более одного предложения или используя союз («и», «но», а также знаки препинания, такие как запятые), то вы, вероятно, видите нарушение принципа единой ответственности. . Еще одно эмпирическое правило состоит в том, чтобы взять каждое из этих предложений/союзов и попытаться изолировать их в один класс. Затем посмотрите, не нарушает ли этот класс SRP. Промойте и повторяйте, пока ничто не нарушит SRP.
Звучит просто, но, как и в шахматах, на изучение уходят минуты, а на освоение уходит целая жизнь.
person
sisyphus
schedule
05.01.2017