Шаблон построения и LSP

#oop #design-patterns #solid-principles

#ооп #дизайн-шаблоны #твердые принципы #шаблоны проектирования #solid-принципы

Вопрос:

Я просматривал шаблон построения, и у меня возникла пара вопросов, которые, по моему мнению, нуждались в разъяснении

  1. Реализован ли шаблон построения через абстрактный класс или через интерфейсы. Есть несколько сообщений, в которых используется интерфейсhttps://sourcemaking.com/design_patterns/builder
    https://refactoring.guru/design-patterns/builder
    …можно перечислить больше
    и другие, использующие абстрактный класс https://www.dofactory.com/net/builder-design-pattern

Примечание: Я думаю, что это должно быть реализовано с использованием абстрактного класса. Это обоснование основано на предположении, что таким образом я могу / не могу реализовать их в производном классе (поскольку может быть вероятность, что несколько конкретных классов их не реализуют)…
Однако это предположение может быть совершенно неверным.

  1. Если приведенное выше предположение неверно, то оно не будет нарушать LSP. Поскольку одно условие в LSP гласит, что вы не можете иметь «не реализованные методы» в вашем производном классе.

Или я совершенно неправильно его понял…

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

1. <мнение> Я думаю, что лучший способ работать со сборщиками — через интерфейсы, а не абстрактные классы. Это будет странно, когда вы вызываете функцию в построителе, например setX , для создания исключения, такого как Unimplemented Function . </мнение>

2. Итак, что произойдет, если у меня есть конкретный класс, который реализует IBuilder и не реализует какой-либо один метод. Разве это не было бы нарушением LSP?..

3. Да, на мой взгляд, наличие нереализованной функции в таком шаблоне — это неприятный запах, и это усложнит обслуживание и тестирование вашего кода, потому что это заставляет клиентский код знать, какие методы недоступны в разных вариантах использования.

4. Что вы имеете в виду под «не внедрением» метода? Если метод не реализован, этот конкретный класс должен быть объявлен «абстрактным» для компиляции, поэтому его нельзя создать, поэтому он не может нарушать LSP. Это то же самое для реализации интерфейса или расширения абстрактного класса.

Ответ №1:

Это стало слишком длинным для комментария…

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

При этом шаблон GoF Builder чрезмерно сложен. Шаблон полезен даже без полиморфизма. И я думаю, что именно так это чаще всего реализуется. Если вы используете Java, это будет шаблон построения Джоша Блоха из Effective Java.

Я не хочу отклонять вопрос LSP, но если реальная цель здесь — научиться эффективно использовать конструктор, то мой совет — игнорировать (устаревшую) версию из GoF и посмотреть на современную реализацию, где этот вопрос не возникает. Если вы действительно хотели спросить о LSP, то я предлагаю новый вопрос, посвященный конкретно этой теме, отдельно от шаблона построения.

Чтобы более непосредственно ответить на вопросы в OP,

  1. Шаблон builder может быть реализован через абстрактные классы или через интерфейсы. Не имеет значения, какой именно. Современные реализации чаще не используют ни то, ни другое.
  2. Соответствие LSP будет зависеть от того, как вы реализуете (и документируете) шаблон. Можно было бы нарушить LSP (или нет), используя интерфейсы или абстрактные классы. Устранение обоих устраняет этот вопрос.