Статьи

Расширение для TellDontAsk

Более пяти лет Мартин Фаулер определил одну из самых больших проблем в объектно-ориентированном программировании в своей знаменитой статье TellDontAsk . В своем письме он напомнил программистам, что им следует доверять своим объектам выполнение работы за них, а не просить объекты предоставлять данные, которые они впоследствии будут работать с собой.

С этим я очень согласен, но, конечно, сам по себе этот принцип не гарантирует, что наш код будет объектно-ориентированным. Я думаю, что недостаточно доверять объекту выполнение этой работы — необходимы дополнительные усилия по проектированию, чтобы гарантировать, что указанный объект не вызовет процедурный код в дальнейшем.

TellDontAsk

Tom & Jerry — Blue Cat Blues, Уильям Ханна и Джозеф Барбера

Давайте посмотрим на пример:

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, являются их собственными.