Добавляйте поля и методы в классы, которые наследуются от той же базы, не изменяя базовый класс.

В моем приложении мне нужно добавить некоторые дополнительные функции для сторонних элементов управления.

Примером могут служить TcxLabel и TcxDBLabel (от DevExpress). Оба наследуют от одного и того же базового класса.

Для этих элементов управления я хотел бы добавить некоторые поля и методы.

Как я это делаю сегодня:

TMycxLabel = class(TcxLabel)
private
  FMyField1: string;
  FMyField2: Integer;
public 
  procedure DoSomething;
end;

 

TMycxDBLabel = class(TcxDBLabel)
private
  FMyField1: string;
  FMyField2: Integer;
public 
  procedure DoSomething;
end;

Так что в основном мне приходится писать все дважды.

Одним из способов достижения этого было бы изменение базового класса, от которого наследуются эти 2 элемента управления. Но это не вариант - классы/пакеты DevExpress не должны изменяться.

Есть ли способ добавить это?


person Thomas    schedule 22.06.2016    source источник
comment
AFAIK нет чистого способа сделать это.   -  person Uwe Raabe    schedule 22.06.2016
comment
Помощники класса @MartynA не позволяют мне объявлять новые поля, только методы.   -  person Thomas    schedule 22.06.2016
comment
Ах да, извините, у меня был старший момент.   -  person MartynA    schedule 22.06.2016
comment
Кажется, кто-то недоволен ответами... Но то, что хочет ОП, невыполнимо.   -  person Free Consulting    schedule 22.06.2016
comment
Вместо добавления этих полей и методов к обоим типам меток вы можете написать класс TcxLabelExt, содержащий эти поля и методы, и добавить такой TcxLabelExt к обоим типам tMycx.... Тогда вам придется написать расширенную функциональность только один раз. Вам придется обрабатывать содержащееся расширение вручную, но это, вероятно, намного проще.   -  person Rudy Velthuis    schedule 23.06.2016


Ответы (3)


Есть ли способ добавить это?

Нет, нет. Любое жизнеспособное решение будет по существу эквивалентно вашему текущему подходу. Поскольку вы хотите, чтобы состояние было связано с экземпляром, вам действительно нужно, чтобы оно было частью экземпляра. Что приводит вас к решению, которое у вас есть.

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

Наиболее эффективным подходом было бы добавление полей в общий базовый класс, но вы исключили это, так как это связано с изменением стороннего кода.

person David Heffernan    schedule 22.06.2016

Способ есть, хотя он сгодится только в том случае, если вам нужно только то, что доступно в базовом классе. Например, если TcxDBLabel наследуется от TcxLabel, вы можете добавить метод (грубо говоря) к обоим, если вы используете только часть TcxLabel (поля, методы и свойства) TcxDBLabel.

Я имею в виду приведение типов.

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

Итак, если вы создадите такой подкласс:

THcxLabel = Class(TcxLabel)
private
  FMyField1: string;
  FMyField2: Integer;
public
  procedure DoSomething;
End;

Затем вы можете добавить это к любому экземпляру класса на основе TcxLabel, например:

THcxLabel(cxLabel1).DoSomething;
THcxLabel(cxDBLabel1).DoSomething;

Как я уже сказал, внутри метода DoSomething вам не будут доступны никакие подробности из TcxDBLabel, но вы сможете использовать ресурсы базового класса.

person nunopicado    schedule 06.07.2017

Не могли бы вы один раз наследовать виртуальный класс (который является «вашим»), определить там новые поля, а затем унаследовать оттуда два новых класса?

Изменить на основе комментариев:

ну, вы могли бы попробовать что-то вроде этого.

В ОБА ваши унаследованные классы просто добавьте один общедоступный член данных, который сам является классом, где вы определяете свои собственные вещи... выглядит так:

TMycxLabel = class(TcxLabel)
public
  MyStuff: TMyStuff;
end;

TMyStuff = class()
private
  FMyField1: string;
  FMyField2: Integer;
public 
  procedure DoSomething;
end;

тогда назовите это как

cxLabel1.MyStuff.DoSomething();

Я понимаю, что это не полностью отвечает на ваш вопрос и не работает для нескольких вариантов использования (таким образом вы не можете получить доступ ко всем атрибутам TMycxLabel из MyStuff), но, возможно, вы можете избежать НЕКОТОРОГО двойного кодирования.

person Jur    schedule 22.06.2016
comment
Когда вы попытаетесь воплотить эту идею в жизнь с помощью некоторого кода, вы поймете, что она нежизнеспособна. - person David Heffernan; 22.06.2016
comment
Ну, меня смутил тот же базовый класс в строке темы. По-видимому, он наследует от двух базовых классов. - person Jur; 22.06.2016
comment
@Jur: да, он наследует два упомянутых класса. Но эти два происходят от одного и того же базового класса. - person Rudy Velthuis; 23.06.2016
comment
Ваше обновление похоже на то, что я бы предложил, хотя я бы сделал его свойством с правильным геттером и сеттером. - person Rudy Velthuis; 23.06.2016