(ищу паттерн) Подмешивание фичи в дерево классов
От: sharez  
Дата: 04.06.17 08:12
Оценка:
Всем привет!

Сначала предыстория. Всё дело идёт в вебе, но это не столь важно.
Допустим, есть класс Dialog — окошко. У нас есть 3 типа отображения (не просто стилизация CSS, а даже разная структура HTML — это действительно требуется).
Сейчас код разных методов (buildDialogHtml(), getCssClass() и т. д.) представляют собой ветвистые if'ы:

protected buildDialogHtml() {
    if (ui == 0)
        this.buildDialogHtmlType0();
    else if (ui == 1)
        this.buildDialogHtmlType1();
    else 
        this.buildDialogHtmlType2();


Парадигма ООП говорит, что такой код можно и нужно разделить на иерархию классов:

- Dialog
  - DialogType0
  - DialogType1
  - DialogType2


OK, делаем приватный конструктор, публичный фабричный метод create(), который и возвращает нам инстанс нужного класса.

Всё бы ничего, но у нас вот была такая иерархия:

- ABaseDialog (lib)
  - VeryCustomUserDialog (user)
  - Dialog (lib)
    - MessageDialog (lib)
    - StandardUserDialog (user)


Как видите, получается, мы не можем вклиниться нашим ООП в такую структуру. Т. е. такое ветвление классов подходит только когда тип UI является гарантированно последним звеном в иерархии.

Как реализовать такую штуку, чтобы было красиво и расширяемо?
Может есть какой-то паттерн? Пока на ум приходит только паттерн делегата: создание какого-то объекта UIType внутри Dialog, которому и делегируются данные методы. Но это плодит кучу кода, навигация по которому так себе, и кажется, что уж лучше if'ы. Кроме того ведь пользователь нашей библиотеки может случайно переопределить метод, который вызывает делегата, и не будет понимать, почему всё сломалось (или сломалось только на конкретном типе UI).
Отредактировано 04.06.2017 8:14 sharez . Предыдущая версия .
Re: (ищу паттерн) Подмешивание фичи в дерево классов
От: kov_serg Россия  
Дата: 04.06.17 11:27
Оценка:
Здравствуйте, sharez, Вы писали:

S>Как реализовать такую штуку, чтобы было красиво и расширяемо?

Используйте фабрику и заставляёте её создавать вам инстансы диалогов.
При добавлении новых диалогов просто регистрируйте их в фабрике.

factory.register("DialogType0",()=> new DialogType0() );
...
factory.register("DialogTypeN",()=> new DialogTypeN() );

...
protected buildDialogHtml() {
  return factory.create(features).buildDialogHtml();
}
Re: (ищу паттерн) Подмешивание фичи в дерево классов
От: itslave СССР  
Дата: 05.06.17 22:33
Оценка:
Здравствуйте, sharez, Вы писали:

S>Всем привет!


S>Сначала предыстория. Всё дело идёт в вебе, но это не столь важно.

Вмесито наследования сделать агрегацию. Паттерны композит, декоратор, и наверное приспособленец — взгляды на эту идею с разных сторон.
Re[2]: (ищу паттерн) Подмешивание фичи в дерево классов
От: sharez  
Дата: 06.06.17 09:17
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, sharez, Вы писали:


S>>Как реализовать такую штуку, чтобы было красиво и расширяемо?

_>Используйте фабрику и заставляёте её создавать вам инстансы диалогов.
_>При добавлении новых диалогов просто регистрируйте их в фабрике.

_>
_>factory.register("DialogType0",()=> new DialogType0() );
_>...
_>factory.register("DialogTypeN",()=> new DialogTypeN() );

_>...
_>protected buildDialogHtml() {
_>  return factory.create(features).buildDialogHtml();
_>}
_>


Взять нужный инстанс будет не проблема. Но наследование классов после этого будет несколько сомнительным...
Re[2]: (ищу паттерн) Подмешивание фичи в дерево классов
От: sharez  
Дата: 06.06.17 09:18
Оценка:
Здравствуйте, itslave, Вы писали:

I>Здравствуйте, sharez, Вы писали:


S>>Всем привет!


S>>Сначала предыстория. Всё дело идёт в вебе, но это не столь важно.

I>Вмесито наследования сделать агрегацию. Паттерны композит, декоратор, и наверное приспособленец — взгляды на эту идею с разных сторон.

Спасибо, посмотрю ещё раз на них. Но сколько не смотрел — выходит слишком сложно. Наследование самое то, но накладывает ограничения.
Re[3]: (ищу паттерн) Подмешивание фичи в дерево классов
От: itslave СССР  
Дата: 06.06.17 10:34
Оценка: +1
Здравствуйте, sharez, Вы писали:

S>Спасибо, посмотрю ещё раз на них. Но сколько не смотрел — выходит слишком сложно. Наследование самое то, но накладывает ограничения.

Да чего там сложного то?
А серьезней, наследование накладывает слишком много ограничений и привносит очень сильную связность в код, что чаще плохо чем хорошо
Re[4]: (ищу паттерн) Подмешивание фичи в дерево классов
От: sharez  
Дата: 06.06.17 14:01
Оценка:
Здравствуйте, itslave, Вы писали:

I>Здравствуйте, sharez, Вы писали:


S>>Спасибо, посмотрю ещё раз на них. Но сколько не смотрел — выходит слишком сложно. Наследование самое то, но накладывает ограничения.

I>Да чего там сложного то?

Сложно потом всё это читать. Особенно через год после написания.

I>А серьезней, наследование накладывает слишком много ограничений и привносит очень сильную связность в код, что чаще плохо чем хорошо


Об чем и речь
Re[5]: (ищу паттерн) Подмешивание фичи в дерево классов
От: Mr.Delphist  
Дата: 14.06.17 10:00
Оценка:
Здравствуйте, sharez, Вы писали:

S>Здравствуйте, itslave, Вы писали:


I>>Здравствуйте, sharez, Вы писали:


S>>>Спасибо, посмотрю ещё раз на них. Но сколько не смотрел — выходит слишком сложно. Наследование самое то, но накладывает ограничения.

I>>Да чего там сложного то?

S>Сложно потом всё это читать. Особенно через год после написания.


Дело привычки. Помнится, на одном проекте у нас при виде STL Заказчик вздыхал "читать тяжело". Ничего, затем обвыкся. Сам я тоже при виде LINQ сперва впадал в состояние "ШТА?". Ничего, тоже обвыкся.
Re: (ищу паттерн) Подмешивание фичи в дерево классов
От: rm822 Россия  
Дата: 28.06.17 19:28
Оценка:
S>Может есть какой-то паттерн?
Visitor он называется
Re: (ищу паттерн) Подмешивание фичи в дерево классов
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.06.17 04:38
Оценка:
Здравствуйте, sharez, Вы писали:

S>Всем привет!


S>Сначала предыстория. Всё дело идёт в вебе, но это не столь важно.

S>Допустим, есть класс Dialog — окошко. У нас есть 3 типа отображения (не просто стилизация CSS, а даже разная структура HTML — это действительно требуется).

S>Как видите, получается, мы не можем вклиниться нашим ООП в такую структуру. Т. е. такое ветвление классов подходит только когда тип UI является гарантированно последним звеном в иерархии.

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

S>Как реализовать такую штуку, чтобы было красиво и расширяемо?

Стандартным решением будет вынести "способ отображения" в отдельную иерархию классов, например DialogRenderer. Вся информация о том, как генерируется диалог, будет сосредоточена в каждом из потомков.
S>Может есть какой-то паттерн? Пока на ум приходит только паттерн делегата: создание какого-то объекта UIType внутри Dialog, которому и делегируются данные методы. Но это плодит кучу кода, навигация по которому так себе, и кажется, что уж лучше if'ы. Кроме того ведь пользователь нашей библиотеки может случайно переопределить метод, который вызывает делегата, и не будет понимать, почему всё сломалось (или сломалось только на конкретном типе UI).
Это скорее не делегат, а стратегия. Впрочем, возможны варианты:
1. Вся связь диалога и отображения запихана в один виртуальный метод Dialog.Render(DialogRenderer renderer)
2. Рендерер скармливается диалогу при конструировании, и вызывается по мере необходимости dialog = new VeryCustomDialog(renderer)
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.