Нарушают ли методы "возврата успеха" принцип единой ответственности?
public class FooList {
public boolean add(Foo item) {
int index = indexOf(item.getKey());
if (index == -1) {
list.add(item);
}
return index == -1;
}
}
Поскольку это добавляет элемент и возвращает значение успеха, нарушает ли он принцип единоличной ответственности? Если так, имеет ли это значение?
Альтернативой будет выбрасывать исключение:
public class FooList {
public boolean add(Foo item) throws FooAlreadyExistsException {
int index = indexOf(item.getKey());
if (index == -1) {
list.add(item);
} else {
throw new FooAlreadyExistsException();
}
}
}
Но будет ли это также нарушать принцип единоличной ответственности? Кажется, что у метода есть две задачи: если элемент не существует, добавьте его; иначе, брось исключение.
Дополнительный вопрос: не нарушают ли методы, которые могут возвращать нуль, принцип единственной ответственности? Вот пример:
public class FooList {
public Foo getFoo(String key) {
int index = indexOf(key);
return (index == -1) ? null : list.get(index);
}
}
Возвращает ли Foo или null, в зависимости от ситуации, "выполнение двух вещей"?
1 ответ
Как насчет этого:
public class MyVector{
private int[] data;
private int count;
public void add(int value){
data[count]=value;
++count;
}
}
add
делает две вещи - это обновления data
и приращения count
, Согласно правилу единой ответственности, я должен был разделить его на две функции:
public void MyVector{
private int[] data;
private int count;
public void add(int value){
data[count]=value;
}
public void inc(){
++count;
}
}
что, очевидно, разрушает саму основу ООП. Я хочу data
а также count
изменить вместе - вот в чем смысл объединять их в одном классе!
Вы не очень далеко продвинетесь, если примените правило единственной ответственности, как это. Если каждый метод может делать только одну вещь, тогда вся программа может делать только одну вещь, и когда определение одной вещи похоже на определение, использованное в приведенном выше примере, ваша программа не может сделать ничего интересного.
Дело в том, что не так работает правило единственной ответственности:
Вы не должны стремиться писать методы, которые не могут быть определены таким образом, который определяет более чем одну вещь. Вместо этого вы должны написать метод, который может быть осмысленно и в достаточной степени определен так, чтобы указывать только одну вещь, которую они делают.
Вы не должны определять одну вещь на основе реализации - вы должны определять ее на основе абстракции класса, в котором размещается метод.
Это будет немного спорным: Вы должны быть более строгими в отношении побочных эффектов и менее строгих в отношении возвращаемых значений. Причина заключается в том, что пользователю ваших методов легче игнорировать возвращаемые значения, чем игнорировать побочные эффекты.
Исключения никогда не должны учитываться как "метод делает другое". Они не являются частью описания того, что делает метод - они являются исключением из этого, что происходит только в том случае, если что-то идет не так. Вот и весь смысл исключений.
Теперь давайте посмотрим на ваш метод. Реализация состоит из трех вещей: проверка существования, добавление элемента и возврат результата успеха. Но если вы посмотрите на абстракцию, вы можете определить ее как добавление элемента, если он не существует - и это одна вещь!
Да, он также что-то возвращает, но возвращаемые значения можно легко игнорировать, поэтому я бы не посчитал это "другой вещью". Пользователи метода будут использовать его для добавления элементов, поэтому они могут игнорировать возвращаемые значения, если им это не нужно. Если бы все было наоборот, и они использовали ваш метод для проверки существования элементов, они не смогли бы игнорировать побочный эффект добавления элемента, и это было бы плохо. Очень плохой. Но поскольку "дополнительная вещь" - это возвращаемое значение (или исключение), а не побочный эффект - с вашим методом проблем нет.
Самое важное правило дизайна - не слепо следовать правилам дизайна.