Более пяти лет Мартин Фаулер определил одну из самых больших проблем в объектно-ориентированном программировании в своей знаменитой статье TellDontAsk . В своем письме он напомнил программистам, что им следует доверять своим объектам выполнение работы за них, а не просить объекты предоставлять данные, которые они впоследствии будут работать с собой.
С этим я очень согласен, но, конечно, сам по себе этот принцип не гарантирует, что наш код будет объектно-ориентированным. Я думаю, что недостаточно доверять объекту выполнение этой работы — необходимы дополнительные усилия по проектированию, чтобы гарантировать, что указанный объект не вызовет процедурный код в дальнейшем.
Давайте посмотрим на пример:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
/** * All employees of a company. * You can hire more, fire some of them, give them a raise etc. \*/ public final class AllEmployees implements Employees { //constructor //other methods from Employees interface (hire, fire, raise etc) @Override public List<Employee> filter( final Map<String, String> skills) { //return the List of those who have the specified skills. } } |
Приведенный выше класс создаст надлежащий объект, который уважает принцип мистера Фаулера: он позаботится о сотрудниках и даже отфильтрует их для нас, не задавая вопросов. Тем не менее, это может привести к некоторому ущербу вокруг, и вот почему: после того, как мы выполним фильтрацию, у нас останется List
который различает всех!
Эти отфильтрованные сотрудники никогда не получат повышение? Они никогда не будут уволены, или мы никогда не будем нанимать кого-то с такими же навыками (одинаковыми фильтрами)? Конечно, мы все еще хотим поднять, уволить или нанять кого-то похожего, но мы теперь вне контекста, у нас теперь просто тупой List
в наших руках: чтобы работники в этом списке имели одинаковые права и обязательства, как и все остальное, нам нужно будет написать процедурный код (может быть, много кода).
Вот что, я думаю, мы должны сделать: мы должны добавить новую реализацию Employees
, называемую FilteredEmployees
, которая взяла бы эту Карту в своем конструкторе и удостоверилась, что она обрабатывает только тех сотрудников, которые имеют навыки, которые мы просили. Таким образом, они по-прежнему работают в одной компании, и ничего не изменилось, кроме того, что теперь мы знаем их лучше, мы знаем, что у них есть некоторые навыки, которых нет у других. Нам не нужно будет писать код для обработки или преобразования List
, у нас все еще будет экземпляр Employees
. Теперь наш класс выглядит так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
/** * All employees of a company. * You can hire more, fire some of them, give them a raise etc. \*/ public final class AllEmployees implements Employees { //constructor //other methods from Employees interface (hire, fire, raise etc) @Override public Employees filter( final Map<String, String> skills) { return new FilteredEmployees(..., skills); } } |
Я бы сказал, что идея состоит в том, чтобы попытаться реализовать саму ситуацию, а не сказать объекту, который приведет вас к указанной ситуации. То есть мы реализовали этих отфильтрованных сотрудников, потому что исходный объект не мог выполнить фильтрацию за нас при сохранении контекста. Простое указание объекту сделать это привело бы нас к той же ситуации (работать с людьми, которые обладают данными навыками), но эти люди больше не будут сотрудниками , они будут просто списком.
Я вижу все это как расширение принципа TellDontAsk. Как убедиться, что вы движетесь в правильном направлении, я не совсем уверен. Тем не менее, я думаю, что использование JDK (или любого другого комплекта разработки, который вы используете) является хорошим индикатором: в объектно-ориентированной кодовой базе набор должен быть максимально дискретным . Чем больше вы используете набор для разработки, тем менее объектно-ориентированный ваш код на самом деле или ваши абстракции не лучшие, какими они могут быть. С другой стороны, чем больше вы можете добавлять / изменять / удалять функциональные возможности, просто работая с существующими объектами (или добавляя новые реализации существующих интерфейсов), тем более объектно-ориентированным будет ваше приложение.
PS Вот еще один пример той же идеи.
Опубликовано на Java Code Geeks с разрешения MIhai Andronache, партнера нашей программы JCG. Смотрите оригинальную статью здесь: Расширение для TellDontAsk
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |