5. Один объект — одна задача

5. Один объект — одна задача

Резюме

Концентрируйтесь одновременно только на одной проблеме. Каждый объект (переменная, класс, функция, пространство имен, модуль, библиотека) должны решать одну точно поставленную задачу. С ростом объектов, естественно, увеличивается область их ответственности, но они не должны отклоняться от своего предназначения.

Обсуждение

Хорошая идея, будучи высказанной вслух, должна быть пояснена одним предложением. Аналогично, каждая сущность в программе должна иметь одно ясное предназначение.

Объект с разнородными предназначениями обычно несоразмерно трудно использовать, поскольку он представляет собой нечто большее, чем просто сумму решений, сложностей и ошибок составляющих его частей. Такой объект больше по размеру (зачастую без особых на то причин) и сложнее в применении и повторном использовании. Зачастую такие объекты имеют весьма убогий интерфейс для каждого из своих отдельных предназначений, поскольку частичное перекрытие разных областей функциональности приводит к невозможности четкой реализации в каждой из них.

Объекты с разнородными функциями обычно трудны для проектирования и реализации. "Множественная ответственность" зачастую приводит к тому, что количество возможных вариантов поведения и состояния объектов разрастается в соответствии с законами комбинаторики. Предпочтительнее использовать короткие функции с четко указанным единственным предназначением (см. также рекомендацию 39), маленькие классы, предназначенные для решения одной конкретной задачи, и компактные модули с четко очерченными границами.

Абстракции высокого уровня предпочтительно строить из меньших низкоуровневых абстракций. Избегайте объединения нескольких низкоуровневых абстракций в большой низкоуровневый конгломерат. Реализация сложного поведения из набора простых существенно легче решения обратной задачи.

Примеры

Пример 1. realloc. В стандарте С функция realloc пользуется дурной славой плохо спроектированной функции. Она делает одновременно слишком много дел: выделяет память, если ей передано значение NULL, освобождает ее, если передан нулевой размер, перераспределяет ее на том же месте, если это возможно, или перемещает ее, если такое перераспределение невозможно. Это уже не просто расширение функциональности. Данная функция обычно рассматривается всеми как пример недальновидного, ошибочного проектирования.

Пример 2. basic_string. В стандарте С++ std::basic_string служит таким же пользующимся дурной славой примером проектирования монолитного класса. В этот раздутый до неимоверных размеров класс добавлены все функции, о которых только можно было подумать. Этот класс пытается быть контейнером, что не совсем ему удается; в нем так и остается неразрешенным вопрос между применением итераторов и индексированием. Кроме того, в нем совершенно необоснованно дублируется множество стандартных алгоритмов. В то же время этот класс оставляет очень мало возможностей для расширения. (См. пример к рекомендации 44).

Ссылки

[Henney02a] • [Henney02b] • [McConnell93] §10.5 • [Stroustrup00] §3.8, §4.9.4, §23.4.3.1 • [Sutter00] §10, §12, §19, §23 • [Sutter02] §1 • [Sutter04] §37-40