Первая серия была тут:
http://18delphi.blogspot.com/2013/03/generic-generic.html
Теперь поговорим немного о примесях.
Теорию можно почитать тут:
http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%81%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)
Мы же немного займёмся практикой.
Посмотрим на определение - "При́месь (англ. mix in) — элемент языка программирования (обычно класс или модуль), реализующий какое-либо чётко выделенное поведение. Используется для уточнения поведения других классов, не предназначен для порождения самостоятельно используемых объектов. В объектно-ориентированных языках программирования является способом реализации классов, отличным от широко используемых принципов, пришедших из языка программирования Simula. Механизм впервые реализован в Flavors. Преимуществом примесей является то, что повышая повторную используемость текстов программ, этот метод избегает многих проблем множественного наследования. Однако при этом метод накладывает свои ограничения."
Тем кто программирует на С++ - "повезло" - у них есть множественное наследование и вопросов "как встроить примесь в существую иерархию классов" - не возникает. Программистам на Delphi - "не повезло". Множественного наследования - нет. Да в общем и слава богу. Ибо примеси это гораздо более узкоспециализированный инструмент, чем множественное наследование.
Про конкретные примеры использования примесей в жизни я напишу отдельно. А сейчас рассмотрим чисто абстрактный пример иллюстрирующий лишь технику встраивания примесных классов в иерархию наследования проектных Классов.
В предыдущей статье у нас был пример:
Перерисуем диаграмму следующим образом:
Видим, что весь функционал Stack'а переехал в StackPrim.
И появилось ещё два класса - TIntStackFromPersisten наследующийся от TPersistent и StackPrim, и класс TIntStackFromComponent наследующийся от TComponent и StackPrim.
Множественное наследование - спросите вы. Логически - да. На уровне стрелочек диаграмм.
Теперь посмотрим как это выглядит на Delphi:
StackPrim.imp.pas:
---------------------------------------------
Stack.imp.pas:
http://18delphi.blogspot.com/2013/03/generic-generic.html
Теперь поговорим немного о примесях.
Теорию можно почитать тут:
http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%81%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)
Мы же немного займёмся практикой.
Посмотрим на определение - "При́месь (англ. mix in) — элемент языка программирования (обычно класс или модуль), реализующий какое-либо чётко выделенное поведение. Используется для уточнения поведения других классов, не предназначен для порождения самостоятельно используемых объектов. В объектно-ориентированных языках программирования является способом реализации классов, отличным от широко используемых принципов, пришедших из языка программирования Simula. Механизм впервые реализован в Flavors. Преимуществом примесей является то, что повышая повторную используемость текстов программ, этот метод избегает многих проблем множественного наследования. Однако при этом метод накладывает свои ограничения."
Тем кто программирует на С++ - "повезло" - у них есть множественное наследование и вопросов "как встроить примесь в существую иерархию классов" - не возникает. Программистам на Delphi - "не повезло". Множественного наследования - нет. Да в общем и слава богу. Ибо примеси это гораздо более узкоспециализированный инструмент, чем множественное наследование.
Про конкретные примеры использования примесей в жизни я напишу отдельно. А сейчас рассмотрим чисто абстрактный пример иллюстрирующий лишь технику встраивания примесных классов в иерархию наследования проектных Классов.
В предыдущей статье у нас был пример:
Перерисуем диаграмму следующим образом:
Видим, что весь функционал Stack'а переехал в StackPrim.
И появилось ещё два класса - TIntStackFromPersisten наследующийся от TPersistent и StackPrim, и класс TIntStackFromComponent наследующийся от TComponent и StackPrim.
Множественное наследование - спросите вы. Логически - да. На уровне стрелочек диаграмм.
Теперь посмотрим как это выглядит на Delphi:
StackPrim.imp.pas:
{$IfNDef StackPrim_imp} {$Define StackPrim_imp} ItemsHolder = array of _ItemType_; _StackPrim_ = {mixin} class(_StackPrim_Parent_) private // private fields f_Items : ItemsHolder; public // public methods procedure Push(const anItem: _ItemType_); function Pop: _ItemType_; end;//_StackPrim_ {$Else StackPrim_imp} // start class _StackPrim_ procedure _StackPrim_.Push(const anItem: _ItemType_); var l_L : Integer; begin l_L := Length(f_Items); SetLength(f_Items, l_L + 1); f_Items[l_L] := anItem; end;//_StackPrim_.Push function _StackPrim_.Pop: _ItemType_; var l_L : Integer; begin l_L := Length(f_Items) - 1; Result := f_Items[l_L]; SetLength(f_Items, l_L); end;//_StackPrim_.Pop {$EndIf StackPrim_imp}
---------------------------------------------
Stack.imp.pas:
{$IfNDef Stack_imp} {$Define Stack_imp} _StackPrim_Parent_ = TObject; {$Include StackPrim.imp.pas} _Stack_ = {mixin} class(_StackPrim_) end;//_Stack_ {$Else Stack_imp} {$Include StackPrim.imp.pas} {$EndIf Stack_imp}
--------------------------------------------
StringStack.pas:
unit StringStack; interface type _ItemType_ = AnsiString; {$Include Stack.imp.pas} TStringStack = class(_Stack_) end;//TStringStack implementation {$Include Stack.imp.pas} end.
--------------------------------------------
IntStack.pas:
unit IntStack; interface type _ItemType_ = Integer; {$Include Stack.imp.pas} TIntStack = class(_Stack_) end;//TIntStack implementation {$Include Stack.imp.pas} end.
--------------------------------------------
!!! А вот и два НОВЫХ класса:
--------------------------------------------
IntStackFromPersistent.pas:
unit IntStackFromPersistent; interface uses Classes ; type _ItemType_ = Integer; _StackPrim_Parent_ = TPersistent; {$Include StackPrim.imp.pas} TIntStackFromPersistent = class(_StackPrim_) end;//TIntStackFromPersistent implementation {$Include StackPrim.imp.pas} end.
--------------------------------------------
IntStackFromComponent.pas:
unit IntStackFromComponent; interface uses Classes ; type _ItemType_ = Integer; _StackPrim_Parent_ = TComponent; {$Include StackPrim.imp.pas} TIntStackFromComponent = class(_StackPrim_) end;//TIntStackFromComponent implementation {$Include StackPrim.imp.pas} end.
--------------------------------------------
По-моему - весело :-) Примесь - ОДНА, а включается в ЧЕТЫРЕ разных класса и даже в разные места иерархии наследования.
Попробуйте. Может и вам понравится.
В следующих сериях я постараюсь рассказать - ЗАЧЕМ я это использую.
А для чего нужен комент {mixin}?
ОтветитьУдалить_Stack_ = {mixin} class(_StackPrim_)
1. Для того, чтобы подчеркнуть, что это не настоящий класс, а примесь.
ОтветитьУдалить2. Чтобы искать grep'ом.
3. Мне бы понравилось бы такое ключевое слово компилятора.
ОтветитьУдалить4. У меня Colorer настроен показывать подобные комментарии особым образом.