Рисунок фасада и SRP

В классическом шаблоне Facade один объект обычно обеспечивает упрощенный интерфейс для чего-то более сложного.

Как выразилась «Банда четырех» (настолько близко к «официальному», насколько это возможно…):

Фасад (185) Предоставляет унифицированный интерфейс для набора интерфейсов в подсистеме. Фасад определяет высокоуровневый интерфейс, упрощающий использование подсистемы.

и

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

Или, как говорит Unmesh в https://stackoverflow.com/a/5242476:

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

Принцип единственной ответственности советует нам, что

у класса или модуля должна быть одна и только одна причина для изменения.

Согласно дяде Бобу (http://en.m.wikipedia.org/wiki/Single_responsibility_principle)

Учитывая, что Фасад по своему замыслу ограждает пользователя от множества «причин для изменения», как эти две идеи могут работать вместе? Разве у Фасада не столько причин для изменения, сколько подсистем, от которых зависит его реализация?


person goofballLogic    schedule 16.04.2015    source источник
comment
Каково множество причин, чтобы изменить фасад?   -  person PeeHaa    schedule 16.04.2015
comment
уточню в посте   -  person goofballLogic    schedule 16.04.2015


Ответы (2)


По сути, если ваш класс Facade реализует принцип инверсии зависимостей (он зависит от абстракций, а не от конкретных реализаций), вам не нужно будет изменять его в будущее.

Исключения — если есть ошибка или если вам нужно изменить бизнес-логику Фасада (например, взаимодействие между теми подсистемами, которые он инкапсулирует). Но это не нарушение SRP.

Кстати, кажется, что это неявно упоминается в цитате:

Фасад (185) Предоставляет унифицированный интерфейс для набора интерфейсов в подсистеме.

person Witcher    schedule 21.04.2015
comment
да, в этом есть смысл, за исключением того, что часть задачи фасада состоит в том, чтобы оградить потребителей от изменений в базовых системах. Если это стоит сделать, не означает ли это, что эти системы достаточно сложны, чтобы даже их интерфейсы изменялись по мере их версии? - person goofballLogic; 21.04.2015
comment
Я так и понял. Да, если вам нужно обновить интерфейс конкретной подсистемы - значит, вы нарушили Принцип разделения интерфейсов для этого интерфейса. И не забывайте о принципе Open-Closed - лучше расширять существующий интерфейс/класс, чем обновлять его внутреннее содержимое. Похоже, вы должны знать все принципы SOLID при создании нового класса:) - person Witcher; 21.04.2015

Прежде всего,

Шаблоны и принципы - разные вещи. Шаблон — это проверенное решение проблемы, а принцип — не более чем руководство.

Так что сравнивать их было бы бессмысленно, тем более, что в большинстве случаев они дополняют друг друга.

Что касается определения SRP, «одна причина для изменения» может быть легко объяснена:

Представьте, если вы создадите объект автомобиля, который будет состоять из двигателя, типа и тому подобного. Таким образом, конструкция этого объекта будет выглядеть так:

car = new Car(new Engine(), new Type());

Так что, если вы хотите заменить двигатель этой машины? Тогда вы просто замените экземпляр Engine. Это одна из причин для изменения, поскольку вы не трогаете другие его части.

Что касается фасадов, то данное вами определение слишком общее. Фасад — это просто еще один способ упаковать вещи, которые могут быть недоступны в некоторых средах. Они просто следят за тем, чтобы ваша вещь работала во всех средах. Например, есть очень известный пример слушателей событий в JavaScript:

function click(object, handler){
   if (object.addEventListener != undefined){
     // For major browsers
     object.addEventListener(....);
   } else if (object.attachEvent != undefined){
     // For IE < 7
     object.attachEvent(...)
   } else {
     object.click = handler;
   }
}
person Yang    schedule 16.04.2015
comment
Обновление моего вопроса, чтобы отразить официальное определение фасада GoF - person goofballLogic; 16.04.2015
comment
Ваш пример фасада на самом деле не соответствует классическому определению шаблона фасада, по крайней мере, в кругах OO. - person goofballLogic; 16.04.2015
comment
Определение, которое я описал, взято из книги Росса Хармса и Дастина Диаса, которая называется «Шаблоны проектирования JavaScript» (стр. 141). Что касается отраженных вами изменений, я бы просто реализовал интерфейс для этих фасадов, и поскольку теперь реализация будет зависеть от абстракций, а не от конкретных реализаций, которые решат вашу проблему. - person Yang; 16.04.2015
comment
да, они адаптировали шаблон для мира javascript. Я думаю, что их шаблон хорошо помечен как фасад, потому что он обертывает доступ к нескольким потенциальным базовым подсистемам. Однако он сильно отличается от классического шаблона Facade, в котором объект фасада содержит несколько методов, таких как этот. Следует отметить, что даже в их крошечном фасаде есть как минимум три потенциальных причины для изменений, поскольку поддерживаются три разных стандарта. - person goofballLogic; 16.04.2015