ToDo. Сделать на модели интерфейсы с частичной реализацией.
Интерфейсы обычно маленькие, самодостаточные и непротиворечивые.
Не больше 3-5 методов.
Каждый их которых не выводится из остальных.
Это критерий "хорошего" интерфейса.
При "хорошем" проектировании.
Но бывают такие "монстры" как IStream, IStorage или IDataObject.
Где одни методы интерфейса ЯВНО выводятся через другие. Умолчательно.
IDataObject - тому САМЫЙ яркий пример.
С его GetData и GetDataHere.
Или EnumFormatEtc и EnumFormatEtc.
Ну или бывают маленькие интерфейсы, но у которых методы "по-молчанию" могут выводится из других методов этого же интерфейса.
Например:
Понятное дело, что метод EQ может быть выведен из методов S и Len.
Но "обычно" разработчики "бедные" вынуждены реализовывать такие "дефолнтые методы".
Раз от разу.
Делая одну систематическую ошибку за другой.
Что можно сделать?
Можно конечно сделать "вязанку дефолтных реализаций" в виде глобальных методов. И сказать разработчикам - вот вызывайте эти методы.
Можно просто убрать методы типа EQ с интерфейса и заменить их "вязанкой глобальных методов".
Но!
Иногда интерфейсы они - ЧУЖИЕ, а реализуются в своём коде.
А иногда - УДОБНО иметь умолчательную реализацию с возможностью её переопределять.
Что же делать?
А вот можно сделать на модели у метода интерфейса галку - "имеет умолчательную реализацию".
И интерфейс, у которого есть методы с такими галками - делаем примесь при кодогенерации.
Например поставим такую галку у ICString.EQ.
Тогда при кодогенерации получим примесь:
И пусть наш класс TCString реализует (на модели) интерфейс ICString.
Тогда получаем такой код:
А можно ещё получить TCString1:
По-моему - интересная идея. мне давно такой штуки не хватает.
А можно пойти дальше.
Сделать "галку" трёхпозиционной - abstract/virtual/final.
И если:
abstract - не делаем умолчательную реализацию.
virtual - делаем виртуальную умолчательную реализацию.
final - делаем финальную (статическую) реализацию.
+Виктор Морозов
+Михаил Костицын
+Николай Зверев
Литература:
О шаблонах и примесях
Собственная реализация IUnknown и подсчёт ссылок. И примеси
Коротко. Много написал про "примеси и шаблоны"
И ещё раз про "примеси". Теперь - "серьёзно"
Языки "где так или иначе" возможны примеси
Зачем UML
Завтра думаю - сделаю.
Не самая простая задачка кстати. Там есть подводные камни.
Если мы копируем методы интерфейса в примесь, то в наследниках получаем реализацию этих методов.
Паразитную.
А если не копируем, то непонятно как их там показать.
Хотя есть вариант - "дополнительный цикл" типа %o и %O.
Но опять же - как сказать, что "метод уже реализован"?
Переносить его в PureMixIn?
Всё - ПРОЩЕ - ВООБЩЕ не реализовывать методы у которых стоит галка.
Интерфейсы обычно маленькие, самодостаточные и непротиворечивые.
Не больше 3-5 методов.
Каждый их которых не выводится из остальных.
Это критерий "хорошего" интерфейса.
При "хорошем" проектировании.
Но бывают такие "монстры" как IStream, IStorage или IDataObject.
Где одни методы интерфейса ЯВНО выводятся через другие. Умолчательно.
IDataObject - тому САМЫЙ яркий пример.
С его GetData и GetDataHere.
Или EnumFormatEtc и EnumFormatEtc.
Ну или бывают маленькие интерфейсы, но у которых методы "по-молчанию" могут выводится из других методов этого же интерфейса.
Например:
type ICString = interaface function S: PChar; function Len: Integer; function EQ(const anOther: ICString): Boolean; end;//ICString
Понятное дело, что метод EQ может быть выведен из методов S и Len.
Но "обычно" разработчики "бедные" вынуждены реализовывать такие "дефолнтые методы".
Раз от разу.
Делая одну систематическую ошибку за другой.
Что можно сделать?
Можно конечно сделать "вязанку дефолтных реализаций" в виде глобальных методов. И сказать разработчикам - вот вызывайте эти методы.
Можно просто убрать методы типа EQ с интерфейса и заменить их "вязанкой глобальных методов".
Но!
Иногда интерфейсы они - ЧУЖИЕ, а реализуются в своём коде.
А иногда - УДОБНО иметь умолчательную реализацию с возможностью её переопределять.
Что же делать?
А вот можно сделать на модели у метода интерфейса галку - "имеет умолчательную реализацию".
И интерфейс, у которого есть методы с такими галками - делаем примесь при кодогенерации.
Например поставим такую галку у ICString.EQ.
Тогда при кодогенерации получим примесь:
type _CString_ = class(_CString_Parent_) protected function EQ(const anOther: ICString): Boolean; virtual; end;//_CString_ ... function _CString_.EQ(const anOther: ICString): Boolean; begin // - тут умолчательная реализация end;
И пусть наш класс TCString реализует (на модели) интерфейс ICString.
Тогда получаем такой код:
type _CString_Parent_ = TInterfacedObject; {$Include CString.imp.pas} TCString = class(_CString_, ICString) protected function S: PChar; function Len: Integer; //function EQ(const anOther: ICString): Boolean; // - Реализован выше, в _CString_ end;//TCString
А можно ещё получить TCString1:
type _CString_Parent_ = TInterfacedObject; {$Include CString.imp.pas} TCString1 = class(_CString_, ICString) protected function S: PChar; function Len: Integer; function EQ(const anOther: ICString): Boolean; override; // - Тут перекрываем умолчательную реализацию end;//TCString1
По-моему - интересная идея. мне давно такой штуки не хватает.
А можно пойти дальше.
Сделать "галку" трёхпозиционной - abstract/virtual/final.
И если:
abstract - не делаем умолчательную реализацию.
virtual - делаем виртуальную умолчательную реализацию.
final - делаем финальную (статическую) реализацию.
+Виктор Морозов
+Михаил Костицын
+Николай Зверев
Литература:
О шаблонах и примесях
Собственная реализация IUnknown и подсчёт ссылок. И примеси
Коротко. Много написал про "примеси и шаблоны"
И ещё раз про "примеси". Теперь - "серьёзно"
Языки "где так или иначе" возможны примеси
Зачем UML
Завтра думаю - сделаю.
Не самая простая задачка кстати. Там есть подводные камни.
Если мы копируем методы интерфейса в примесь, то в наследниках получаем реализацию этих методов.
Паразитную.
А если не копируем, то непонятно как их там показать.
Хотя есть вариант - "дополнительный цикл" типа %o и %O.
Но опять же - как сказать, что "метод уже реализован"?
Переносить его в PureMixIn?
Всё - ПРОЩЕ - ВООБЩЕ не реализовывать методы у которых стоит галка.
Надо ещё думать над этим.
ОтветитьУдалить