Страницы

Поиск по вопросам

среда, 13 марта 2019 г.

Трактовка принципа Открытости-Закрытости

Пример с дополнением интерфейса:
class Playback { private Media current;
public void play(Media media) { current.stop(); current = media; current.play(); }
public void next() { Media media // получение следующей по какому либо алгоритму play(media); }
public void prev() { Media media // получение предыдущей по какому либо алгоритму play(media); } }
Пример с добавлением классов операций:
class Playback { private Media current;
public Media current() { return current; }
public void play(Media media) { current.stop(); current = media; current.play(); } }
abstract class PlayOperation { private Playback playback;
public void execute() { Media media = provide(); playback.play(media); }
protected abstract Media provide(); }
class NextOperation extends PlayOperation { public Media provide() { Media media // получение следующей по какому либо алгоритму return media; } }
class PrevOperation extends PlayOperation { public Media provide() { Media media // получение предыдущей по какому либо алгоритму return media; } }
class RandomOperation extends PlayOperation { private Random random;
public Media provide() { Media media // получение рандомной return media; } }
Пример с новыми классами выглядит привлекательнее, а стоит ли оно того?


Ответ

Пример с добавлением классов операций
То что вы описали в примере, это почти шаблон проектирования "Посетитель" . NextOperation , PrevOperation , RandomOperation - посетители класса Playback . В данном случае этот шаблон вряд ли обоснован, так как он призван добавлять поведение иерархии классов, и он действительно при работе с иерархией играет на OCP (т.к. необходимость добавления поведения в дерево наследников с помощью добавления метода в базовый класс как-раз нарушит OCP). У вас же класс один Playback - OCP не будет нарушено в первом случае - Playback открыт для расширения наследованием (если конечно поменять private на protected), и закрыт для изменения (это значит, что переписывать его вам не требуется для доработки поведения в наследниках).
Нельзя не увидеть минус второго подхода - вы серьёзно усложняете систему, размазывая простую логику на множество классов ( это Anti-SRP ). Поэтому я бы посоветовал оставить первый вариант, как минимум, когда система простая - так усложнять её нельзя, YAGNI против.
Но если Playback становится базовым классом иерархии - использование посетителей будет уже обосновано, и следует добавить метод visit(PlayOperation operation), при чём возможность посещения Playback - не значит что метод next(), например, обязательно должен быть вынесен в класс-посетитель: в посетителей лучше выносить дополнительные операции, а основные - оставлять внутри класса.

Комментариев нет:

Отправить комментарий