#c_sharp #шаблоны_проектирования
Имеется базовый класс (предположим, Window), у которого огромное число классов-потомков (BlackWindow, TransperentWindow, ...). Предположим, что я хочу добавить в архитектуру класс BorderedWindow, который перегружает пару виртуальных функций родительского класса Window. И далее я хочу, чтобы все имеющиеся классы-потомки могли создаваться как от Window, так и от BorderedWindow. Проблему можно проиллюстрировать следующим кодом: class Window { public virtual Rectangle ClientArea() { return new Rectangle(0, 0, 100, 50); } } class BlackWindow : Window { public BlackWindow(Window window) { ... } } class BorderedWindow : Window { public overide Rectangle ClientArea() { return new Rectangle(5, 5, 110, 60); } } Window window = new Window(); BorderedWindow borderedWindow = new BorderedWindow(); new BlackWindow(window).ClientArea(); // Rectangle(0, 0, 100, 50), ОК new BlackWindow(borderedWindow).ClientArea(); // Rectangle(0, 0, 100, 50), FAIL! В целом, здесь можно применить паттерн Декоратор. Но этого делать не хочется, так как последуют существенные изменения классов-потомков. Придётся для каждой функции класса Window писать функцию-"обёртку" в каждом классе-наследнике. Для десятка функций и десятка классов объём кода вырастает драматически. Как можно исправить ситуацию?
Ответы
Ответ 1
Почему бы тогда не «Стратегия»? Вместо довольно неудобного наследования переходите на прогрессивную композицию. Пусть любой из классов получает ClientStrategy как часть конструктора. interface IClientAreaStrategy { Rectangle ClientArea { get; } } class DefaultClientAreaStrategy : IClientAreaStrategy { Rectangle clientArea = new Rectangle(0, 0, 100, 50); public Rectangle ClientArea { get { return clientArea; } } } class BorderedClientAreaStrategy : IClientAreaStrategy { Rectangle clientArea = new Rectangle(5, 5, 110, 60); public Rectangle ClientArea { get { return clientArea; } } } class Window { protected readonly IClientAreaStrategy clientAreaStrategy; public Rectangle ClientArea { get { return clientAreaStrategy.ClientArea; } } public Window(IClientAreaStrategy clientAreaStrategy) { this.clientAreaStrategy = clientAreaStrategy; } } class BlackWindow : Window { public BlackWindow(Window window) : base(window.ClientStrategy) { // ... } } (Кстати, у нужно ли наследование для BlackWindow? Возможно, вам снова нужна композиция?) Для конкретно этого случая вам не нужен целый интерфейс IClientAreaStrategy, а просто Funcили даже просто Rectangle. Но в более сложном случае понадобится интерфейс.
Комментариев нет:
Отправить комментарий