Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Интерфейсы базовых классов. Давайте обсудим?


Автор: Bose 14.4.2009, 02:54
Давайте обсудим идею.

Я вот тут подумал, что здорово было бы, если бы в Дельфи были определены интерфейсы для базовых классов. Например, был бы интерфейс IList, реализуемый классом TList. IStringList, реализуемый TStringsList и т.п. А особенно классно, было бы если бы были определены интерфейсы реализующие взаимодействие с компонентами.

Например интерфейс:
Код
ICaptionedControl = interface
  property Caption:string;
end;


Если бы все контролы, имеющие свойство Caption(например TLabel; TButton; TCheckBox; TRadioButton; TGroupBox; TBitBtn; TSpeedButton), реализовывали его, было бы намного проще изменять и считывать у них Caption. Хотя, подобное на практике нужно только, когда начинаешь реализовывать собственный механизм перевода программы.

Пример с Db-control-ами

Более полезным было бы применение интерфейсов в Db-контролах. Например, имея интерфейсы:
Код
IDataSourceProperty = interface
  property Datasource: Idatasource;
end;
IDataFieldProperty = interface
  property DataFieldName:string;
  function GetDataField: IField;
end;

IReadOnly = interface
  property ReadOnly: Boolean;
end;


Можно было бы упростить работу с Db-контролами в разы, просто проверяя, реализует ли контрол соответствующий интерфейс. Это было бы полезно для обработки прав доступа в программе. Например, если у пользователя нет прав на работу с определённым полем в базе, то и в приложении, все контролы использующие данное поле можно спрятать, или сделать их доступными только для чтения. 

А то сейчас, чтобы реализовать что-то подобное, приходится либо использовать TypInfo, либо проверять классы вручную:
Код

procedure ValidateControlsField(Sender: TObject);
var
  tmpField: Tfield;
begin
If aControl is TDbEdit then
  tmpField := TDbEdit(aControl).DataField
else If aControl is TDbMemo then
  tmpField := TDbMemo(aControl).DataField
else If aControl is TDbComboBox then
  tmpField := TDbComboBox(aControl).DataField;
end;


А всё потому, что TDbEdit наследуется от TCustomMaskEdit, TDbComboBox от TCustomComboBox, а TDbMemo от TCustomMemo.

В случае с интерфейсами, код выглядел бы примерно так:
Код

procedure ValidateControlsField(Sender: TObject);
var
  tmpDataFieldPropertyI: IDataFieldProperty;
begin
  if Supports(Sender, IDataFieldProperty, tmpDataFieldPropertyI) then
  begin
    // работаем с Tfield, точнее IField
  end; 
end;


Где ещё это было бы полезно?
Если в приложении вместо приведения типов, использовать интерфейсы, это увеличит возможность повторного использования кода.

При создании расширений(плагинов).

Можно было бы вводить поддержку плагинов, использующих функционал классов, без возни с COM или BPL(которые требуют, чтобы и exe и bpl были скомпилированы одной версией компилятора).

Автоматическое уничтожение объектов. Вводить меньше кода.

Вместо того, чтобы писать так:
Код

procedure SomeProcedure; 
var tmpSL: TStringList; 
begin 
  tmpSL:= TStringList.Create; 
  try 
    // работаем с tmpSL
  finally 
    tmpSL.Free; 
  end; 
end;


Можно было бы писать так:

Код

procedure SomeProcedure;
var tmpSL: IStringList; 
begin 
  tmpSL:= TStringList.Create; 
  // работаем с tmpSL
end; // tmpSL будет автоматически освобождена.


Самое главное

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

Например:

Сейчас у меня в проектах используются стандартные Db-контролы(TDbEdit, TDbComboBox). Чтобы заменить из на другие аналогичные Db-контролы(например http://www.ehlib.com/-овские), придётся заменить компоненты на форме, а также пройтись по коду в поисках явной проверки типов(if Sender is TDbEdit then …). Если бы были интерфейсы, и в коде использовались они, то, многое бы работало без изменений.


Давайте обсудим

Что вы думаете об этой идее?

p.s. У Delphi появился http://delphi.uservoice.com/pages/general. И я добавил туда эту идею. http://delphi.uservoice.com/pages/general/suggestions/155605-add-interface-support-for-basic-vcl-classes(можно голосовать без регистрации):
http://delphi.uservoice.com/pages/general/suggestions/155605-add-interface-support-for-basic-vcl-classes

p.p.s. Если не сложно, то проголосуйте ещё за http://delphi.uservoice.com/pages/general/suggestions/155472-fully-support-firebird-database-out-of-the-box.(навряд ли это, что-то изменит, но ведь попытка - не пытка.=))

p.p.p.s. http://tdelphi.blogspot.com/2009/04/delphi-vcl.html.

Автор: pseud 14.4.2009, 09:40
Цитата(Bose @  14.4.2009,  02:54 Найти цитируемый пост)
Давайте обсудим идею.

Цитата(Bose @  14.4.2009,  02:54 Найти цитируемый пост)
Я вот тут подумал, что здорово было бы, если бы в Дельфи были определены интерфейсы для базовых классов.

Поддерживаю.
Ибо SetOrdProp, SetFloatProp, GetVariantProp (TypInfo) - хоть и делают свое дело, но с интерфейсами было бы куда легче, гибче и красивее.

Автор: THandle 14.4.2009, 10:13
Все это прекрасно, я полностью поддерживаю... Но мне кажется что никогда этого не сделают =)

Автор: jsa 14.4.2009, 10:50
Поддерживаю, проголосовал  smile 

Автор: cemick 14.4.2009, 10:54
Это было бы удобно, в каждом крупном проекте приходится что то подобное каждый раз реализовывать

Автор: Keeper89 14.4.2009, 22:57
Согласен, идея отличная.

Автор: Bainer 17.4.2009, 21:07
Согласен, проголосовал и за Интерфейсы и за FB

Автор: Лапоть 17.4.2009, 21:33
Цитата(Bose @  14.4.2009,  02:54 Найти цитируемый пост)
если у пользователя нет прав на работу с определённым полем в базе
То кто/что мешает просто либо сделать колонку в гриде невидимой, либо отселектить данные соответствующим образом?
Дискуссия напомнила старую байку о том, кем бы была бабушка, если бы у неё ... 

Автор: Alexeis 17.4.2009, 22:20
  Плохо голосуем товарищи. Я уже 2 раза успел по +3 поставить smile .

Автор: Bose 18.4.2009, 02:26
Спасибо всем, кто проголосовал! 
http://delphi.uservoice.com/pages/general/suggestions/155605-add-interface-support-for-basic-vcl-classes, наконец вышла на первую страницу форума. Теперь её будет проще заметить. =)

Хорошая новость номер 2. Codegear наконец-то просмотрели указанные там идеи, и присвоили некоторым статусы Accepted и Under Review, что говорит о том, что тот форум всё-таки просматривается.

Может у кого-нибудь есть, ещё какие-нибудь примеры того, какими могли бы быть интерфейсы. Будет здорово, если Вы их напишите(http://delphi.uservoice.com/pages/general/suggestions/155605-add-interface-support-for-basic-vcl-classes или здесь).


Цитата(Лапоть @  17.4.2009,  20:33 Найти цитируемый пост)
То кто/что мешает просто либо сделать колонку в гриде невидимой, либо отселектить данные соответствующим образом?
Дискуссия напомнила старую байку о том, кем бы была бабушка, если бы у неё ... 

Лапоть, не в тему. Ничто не мешает. 
Проблемы нет. Есть идея, о том как сделать работу удобнее, и кое-какие примеры. 

Автор: bems 18.4.2009, 02:58
ну чтобы использовать автоматическое уничтожение объектов мало поддержки интерфейсов ,нужно еще наследоваться от TInterfacedObject, а это хоть и не значительное, но все-же изменение в иерархии.

Кроме того это
Цитата(Bose @  14.4.2009,  02:54 Найти цитируемый пост)
procedure SomeProcedure;
var tmpSL: IStringList; 
begin 
  tmpSL:= TStringList.Create; 
  // работаем с tmpSL
end; // tmpSL будет автоматически освобождена.

работает только если мы точно знаем что интерфейс поддерживается, а иначе все равно нужно добавлять защищенный блок

Автор: Лапоть 18.4.2009, 13:23
Цитата(Bose @  18.4.2009,  03:26 Найти цитируемый пост)
Лапоть, не в тему. Ничто не мешает. 
Проблемы нет. Есть идея, о том как сделать работу удобнее, и кое-какие примеры.

Так я и высказал своё мнение по этому вопросу. Ежели оно вам не понравилось - извиняйте!

Автор: CodeMonkey 18.4.2009, 13:41
Цитата(bems @  18.4.2009,  02:58 Найти цитируемый пост)
ну чтобы использовать автоматическое уничтожение объектов мало поддержки интерфейсов ,нужно еще наследоваться от TInterfacedObject

Не обязательно - как альтернатива: можно реализовать эту функциональность в первом классе с интерфейсом по ветке наследования.

2 Bose: а чего ж на QC не добавил как suggestion?

Автор: Bose 18.4.2009, 15:17
Цитата(CodeMonkey @  18.4.2009,  12:41 Найти цитируемый пост)
2 Bose: а чего ж на QC не добавил как suggestion? 

Мне очень не нравится интерфейс QC. =(

Но я кое-как разобрался, и с помощью встроенной в Delphi штуки с мегаужасным интерфейсом запостил репорт: http://qc.embarcadero.com/wc/qcmain.aspx?d=73087. Имеющие аккаунт и голоса там, да будут услышаны.  smile 

Автор: kemiisto 18.4.2009, 15:46
Bose, читал-читал и так ничего и не понял. smile Проголосовал за вещи, которые считаю более важными. smile 

Автор: Alexeis 21.4.2009, 09:40
  Хотя надо отметить, что интерфейсы не слабо увеличивают размер каждого экземпляра объекта. Например исполнение 4х интерфейсов в объекте 4 * 4 = 16 байт плюс к размеру. Учитывая, что TObject будет уже исходно не 4, а 8 байт. 6й, 7й наследник будут уже 7 * 4 = 28 байт дополнительно. В принципе не критично учитывая что на каждый объект и так добавляется + 10 байт от менеджера кучи, но все равно расход имеется. Хорошо было б если это добро включалось директивой, $IFDEF STANDART_INTERFACESES. 
  Кстати есть вариант написать препроцессор и самому такое сделать(хотя бы до 5-10 самых используемых классов), после чего перекомиллировать VCL и попробовать скомпилировать так большой проект.

Автор: Bose 21.4.2009, 11:21
Цитата(Alexeis @  21.4.2009,  08:40 Найти цитируемый пост)
Кстати есть вариант написать препроцессор и самому такое сделать(хотя бы до 5-10 самых используемых классов), после чего перекомиллировать VCL и попробовать скомпилировать так большой проект.


Есть и другой. http://kazav.blogspot.com/2009/04/delphi.html, навешивающий хук на метод TObject.GetInterface позволяющий добавить поддержку новых интерфейсов в старые классы. smile 

Пример показывает как добавить поддержку интерфейса ICaptionedControl к некоторым базовым контролам. Его легко можно доработать, реализовав пример с интерфейсами
Код

IDataSourceProperty = interface
  property Datasource: Idatasource;
end;
IDataFieldProperty = interface
  property DataFieldName:string;
  function GetDataField: IField;
end;
IReadOnly = interface
  property ReadOnly: Boolean;
end;


p.s. it's a kind of magic

Автор: mes 21.4.2009, 20:09
Цитата(Alexeis @  21.4.2009,  08:40 Найти цитируемый пост)
Например исполнение 4х интерфейсов в объекте 4 * 4 = 16 байт плюс к размеру. 

это только указатели на виртуальную таблицу, а еще сами таблицы увеличат размер библиотеки, хотя это уже мелочи.

Цитата(Alexeis @  21.4.2009,  08:40 Найти цитируемый пост)
Хорошо было б если это добро включалось директивой, $IFDEF STANDART_INTERFACESES. 

имхо, можно не изменяя иерархии добавить адаптеры, предоставляющие нужные интерфейсы. 


Автор: Альт 25.4.2009, 07:52
Лет шесть назад купил Rinse... от http://www.dimeric.com... в комплекте идет их пакет Utils... посмотрите на интерфейсы:
http://www.dimeric.com/DSWeb/doc/html/dsutil/symref.html
Все объекты VCL легко обертываются интерфейсами вот такими методами:
http://www.dimeric.com/DSWeb/doc/html/dsutil/004138.html
где первый параметр - это любой созданный вами наследник TStrings (обычно TStringsList), а второй - это признак, что объект надо разрушить при занулении счетчика интерфейса. Аналогично с 
http://www.dimeric.com/DSWeb/doc/html/dsutil/003889.html и т.д.
Библиотека функционально огромна и стоит своих денег.

Автор: CodeMonkey 25.4.2009, 14:04
Цитата(Альт @  25.4.2009,  07:52 Найти цитируемый пост)
Библиотека функционально огромна и стоит своих денег

Да, только развитие её остановилось в 2005-м ;)

Автор: Альт 25.4.2009, 15:39
CodeMonkey, сложно придумать что-то новое в IList и IDataSet... стабильность у пакета 100%... покупал я ради Rinse, а утилиты пришли сверху довеском, как нижний слой реализации и свои деньги отработали еще на первом проекте ) пишу на семерках, но проекты собираются и на d2009 без всяких проблем... будет нужно, переведу... у меня сырцы ;))
А писал я к тому, что не требуется оборачивать VCL интерфейсами... это 100 лет умеют делать и сторонние библиотеки... к примеру еще есть RemObject ;)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)