SW-Design: адаптеры для иерархии классов в Delphi (Generics vs. Downcast) - PullRequest
6 голосов
/ 17 июня 2011

Я хотел бы получить некоторые предложения по следующей проблеме: Допустим, вы хотите написать адаптеры для элементов управления VCL.Все адаптеры должны иметь одинаковый базовый класс, но отличаться друг от друга специальными элементами управления (например, получение значения из TEdit отличается от получения значения из TSpinEdit).Итак, первая идея - создать иерархию классов, такую ​​как

TAdapter = class
end;

TEditAdapter = class (TAdapter)
end;

TSpinEditAdapter = class (TAdapter)
end;

Теперь я хочу ввести поле для хранения ссылки на элемент управления vcl.В моих специальных адаптерах я хочу - конечно - работать с конкретным подклассом.Но базовый класс также должен содержать ссылку (например, если я хочу использовать адаптер, чтобы сделать элемент управления видимым).

Возможность 1 (Downcast в Property Accessor):

TAdapter = class
protected
  FCtrl : TControl;
end;

TEditAdapter = class (TAdapter)
  public
    property Control : TEdit read GetControl write Setcontrol;
end;
{...}
function TEditAdapter.GetControl : TEdit;
begin
  Result := FCtrl as TEdit;
end;

Поэтому, если я реализую определенный метод, я работаю со свойством Control, если я что-то делаю в своем базовом классе, я использую защищенныйfield.

Возможность 2 (Используйте базовый базовый класс):

TAdapter = class
end;

TAdapter <T : TControl> = class (TAdapter)
protected
  FCtrl : T;
end;

TEditAdapter = class (TAdapter <TEdit>)
end;

Какое решение вы бы предпочли?Или есть третье решение, которое даже лучше?

С уважением,

Кристиан

Ответы [ 2 ]

4 голосов
/ 17 июня 2011

Вы не можете использовать обобщения для решения этой проблемы, потому что вы окажетесь в одной из двух ситуаций:

  • Свойство или метод, который вы хотите «адаптировать» (свойство Textнапример) определяется в классе предков.В этом случае вам не нужны дженерики, потому что вы можете использовать один адаптер для предка и решить проблему для всех потомков.
  • Свойство или метод вводится классом, который вы хотите адаптировать.В этом случае вы не можете использовать универсальные шаблоны, потому что для доступа к свойству или методу вам понадобится ограничение универсального типа для данного данного типа .Пример.Допустим, вам нужен адаптер для свойства Text TMyClass.Давайте предположим, что TMyClass является тем, который вводит свойство Text.Чтобы получить к нему доступ, вам нужно объявить универсальный тип как TGeneric<T:TMyClass>, и это на самом деле не является универсальным.

По моему мнению, лучше всего написать конкретные адаптеры для каждого класса, так какв вашем первом варианте.Возможно, вы сможете использовать трюки RTTI, чтобы упростить реализацию вашего первого варианта, но я не уверен, что оно того стоит.

0 голосов
/ 17 июня 2011

Обобщенная версия может позволить избежать дублирования кода, по крайней мере, в классе TAdapter. Используя тип T, он позволяет много общего кода.

С другой стороны, из-за иерархии VCL большинство используемых свойств и методов уже будут в TControl. Поэтому я не уверен, что в неуниверсальной реализации будет так много дублированного кода.

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

ИМХО, основанный на обобщении дизайн добавит больше абстракции к реализации, но неуниверсальный, возможно, будет ближе к иерархии VCL, к которой он будет адаптироваться.

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

Для другой (не основанной на VCL) архитектуры адаптера, я бы, вероятно, посоветовал бы чисто общую реализацию снизу вверх.

...