#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. Но в более сложном случае понадобится интерфейс.
Комментариев нет:
Отправить комментарий