http://sergeyteplyakov.blogspot.ru/2014/12/interfaces-vs-abstract-classes.html
Для Delphi эта статья - ОСОБЕННО АКТУАЛЬНО читается.
Особенно в "разрезе" InterlockedIncrenent.
В общем - "мои мысли" Тепляков - озвучил - "более чем".
Одно хочу добавить - у Теплякова нет "количественных оценок", а они - ИМХО - важны.
Если методов - "один-два-пять". Ну в крайнем случае - "десять", то это интерфейс.
Иначе это - "должен быть" - абстрактный класс.
Ибо "количественная оценка" говорит о том, что "такой интерфейс реализовать КРАЙНЕ сложно".
Я про "количественные оценки" и Интерфейсы vs. Абстрактные классы когда-то хотел написать.
Но потом - "забил". Понял, что "не поймут".
"Из своей практики" всё же добавлю.
Вот "это" - НЕ ИНТЕРФЕЙС.
А ужас:
Этот "интерфейс" - НЕВОЗМОЖНО реализовать. БОЛЕЕ одного раза.
Ибо он содержит в себе - МНОЖЕСТВО "побочных знаний".
И "протоколы взаимодействия".
А ЗНАЧИТ - это НЕ ИНТЕРФЕЙС, а "заготовка класса". Пусть и не ЧИСТО абстрактная. Пусть и ЧАСТИЧНО абстрактная.
То что я продемонстрировал выше - это ОДНО из десятков (а то и сотен) ИДИОТСКИХ проектных решений, которые я воплотил в жизнь. Могу продемонстрировать их ВСЕ. С ДЕТАЛЬНЫМ разбором. Был бы только толк.
И кстати - "до конца" проблема станет ясна только под AQTime.
Когда мы УВИДИМ накладные расходы на "подсчёт ссылок". Это уж если про "экономию на спичках".
БЕЗОТНОСИТЕЛЬНО того, что подобные "интерфейсы" в ПРИНЦИПЕ сложно реализовывать.
Или вот ещё:
Это тоже - УЖАС, а НЕ "интерфейс".
И он к нынешнему моменту - распался на НЕСКОЛЬКО интерфейсов и "примесей".
Для Delphi эта статья - ОСОБЕННО АКТУАЛЬНО читается.
Особенно в "разрезе" InterlockedIncrenent.
В общем - "мои мысли" Тепляков - озвучил - "более чем".
Одно хочу добавить - у Теплякова нет "количественных оценок", а они - ИМХО - важны.
Если методов - "один-два-пять". Ну в крайнем случае - "десять", то это интерфейс.
Иначе это - "должен быть" - абстрактный класс.
Ибо "количественная оценка" говорит о том, что "такой интерфейс реализовать КРАЙНЕ сложно".
Я про "количественные оценки" и Интерфейсы vs. Абстрактные классы когда-то хотел написать.
Но потом - "забил". Понял, что "не поймут".
"Из своей практики" всё же добавлю.
Вот "это" - НЕ ИНТЕРФЕЙС.
А ужас:
Il3Canvas = interface(Il3InfoCanvas) {* Канва для рисования } ['{F14964DA-11A9-490F-8D5C-A02BEAF85B84}'] function pm_GetWindowOrg: Tl3Point; procedure pm_SetWindowOrg(const aValue: Tl3Point); function pm_GetSWindowOrg: Tl3SPoint; procedure pm_SetSWindowOrg(const aValue: Tl3SPoint); function pm_GetClipRect: Tl3Rect; procedure pm_SetClipRect(const aValue: Tl3Rect); function pm_GetGlobalClipRect: Tl3Rect; function pm_GetBackColor: Tl3Color; procedure pm_SetBackColor(aValue: Tl3Color); function pm_GetDrawEnabled: Boolean; procedure pm_SetDrawEnabled(aValue: Boolean); function pm_GetDrawSpecial: Boolean; function pm_GetCanDrawSubs: Boolean; function pm_GetShowCursor: Boolean; procedure pm_SetShowCursor(aValue: Boolean); function pm_GetFontIndexSet: Tl3FontIndexes; procedure pm_SetFontIndexSet(aValue: Tl3FontIndexes); function pm_GetPrinted: Boolean; procedure pm_SetPrinted(aValue: Boolean); function pm_GetPenWidth: Integer; function pm_GetPageOrientation: Tl3PageOrientation; procedure pm_SetPageOrientation(aValue: Tl3PageOrientation); function pm_GetSectionExtent: Tl3Point; procedure pm_SetSectionExtent(const aValue: Tl3Point); procedure pm_SetNotFocused(aValue: Boolean); function pm_GetRegionBottomRight: Tl3Point; function Get_EffectiveColors: Il3EffectiveColors; function pm_GetPageSetup: Il3PageSetup; procedure pm_SetPainter(const aValue: Il3HAFPainter); function pm_GetCanvas: TCanvas; function Get_AbortChecker: Il3AbortChecker; procedure Set_AbortChecker(const aValue: Il3AbortChecker); procedure MoveWindowOrg(const Delta: Tl3Point); overload; procedure MoveWindowOrg(const Delta: Tl3SPoint); overload; procedure FillForeRect(const R: Tl3SRect); procedure FillRect(const R: Tl3SRect); overload; procedure FillRect(const R: Tl3Rect); overload; procedure FillEmptyRect(const R: Tl3Rect); overload; procedure FillEmptyRect(const R: Tl3SRect); overload; function FillRgn(const Region: Il3Region): Boolean; function TextOut(const P: Tl3Point; const S: Tl3PCharLen; FC: Tl3Color = clDefault; BC: Tl3Color = clDefault): Tl3Point; procedure SetCaret(const Origin: Tl3Point; const Extent: Tl3Point; Hidden: Boolean = false); procedure IncCaret(aDeltaX: Integer); procedure BeginPaint; procedure StartObject(anObjectID: Integer); procedure SetPageTop; procedure EndPaint; function DrawRgnOrBlock: Boolean; function HasToDraw: Boolean; procedure StretchDraw(const R: Tl3Rect; Graphic: VCLGraphic); procedure DrawSub(const aSubTarget: IUnknown; const R: Tl3Rect; LayerHandle: Integer; const aSub: IUnknown); procedure ExtTextOut(const P: Tl3Point; const R: Tl3Rect; const S: Tl3WString; F: Tl3TextFormatFlag = l3_tffLeft; Dx: PInteger = nil); overload; procedure ExtTextOut(const P: Tl3SPoint; const R: Tl3SRect; const S: Tl3WString; F: Tl3TextFormatFlag = l3_tffLeft; Dx: PInteger = nil); overload; function CaretLineOut(const aSt: Tl3WString; LineHeight: Integer; aHidden: Boolean; var CaretPos: Integer): Tl3Point; {* выводит строку текста высотой LineHeight, со сдвигом курсора отрисовки. устанавливает курсор в CaretPos. возвращает размеры выведенной строки. } function StringOut(const P: Tl3Point; const Text: Tl3WString): Tl3Point; procedure TabbedTextOut(const P: Tl3Point; const R: Tl3Rect; const S: Tl3WString; const aTabStops: Il3TabStops); overload; procedure TabbedTextOut(const P: Tl3SPoint; const R: Tl3SRect; const S: Tl3WString; const aTabStops: Il3TabStops); overload; function NewPage(ByWidth: Boolean = false): Boolean; {* начать новую страницу. } procedure Line(const A: Tl3Point; const B: Tl3Point); overload; {* нарисовать линию. } procedure Line(const A: Tl3SPoint; const B: Tl3SPoint); overload; {* нарисовать линию. } procedure MoveTo(const Pt: Tl3Point); overload; procedure LineTo(const Pt: Tl3Point); overload; procedure MoveTo(const Pt: Tl3SPoint); overload; procedure LineTo(const Pt: Tl3SPoint); overload; function WO(const aRect: Tl3Rect): Tl3SRect; overload; function WO(const aPt: Tl3Point): Tl3SPoint; overload; function WO(const aPt: Tl3SPoint): Tl3SPoint; overload; procedure DrawFocusRect(const aRect: Tl3SRect); procedure StartRegion; procedure FinishRegion; procedure PushWO; procedure PopWO; function GetClientRect: Tl3Rect; property WindowOrg: Tl3Point read pm_GetWindowOrg write pm_SetWindowOrg; {* смещение начала координат в дюймах. } property SWindowOrg: Tl3SPoint read pm_GetSWindowOrg write pm_SetSWindowOrg; {* смещение начала координат в пикселях. } property ClipRect: Tl3Rect read pm_GetClipRect write pm_SetClipRect; {* прямоугольник отсечения. } property GlobalClipRect: Tl3Rect read pm_GetGlobalClipRect; property BackColor: Tl3Color read pm_GetBackColor write pm_SetBackColor; property DrawEnabled: Boolean read pm_GetDrawEnabled write pm_SetDrawEnabled; {* разрешено рисование? } property DrawSpecial: Boolean read pm_GetDrawSpecial; {* рисовать спецсимволы? } property CanDrawSubs: Boolean read pm_GetCanDrawSubs; {* можем рисовать Sub'ы? } property ShowCursor: Boolean read pm_GetShowCursor write pm_SetShowCursor; {* отображать курсор? } property FontIndexSet: Tl3FontIndexes read pm_GetFontIndexSet write pm_SetFontIndexSet; {* текущий набор индексов шрифта. } property Printed: Boolean read pm_GetPrinted write pm_SetPrinted; {* все напечатано? } property PenWidth: Integer read pm_GetPenWidth; {* ширина пера. } property PageOrientation: Tl3PageOrientation read pm_GetPageOrientation write pm_SetPageOrientation; {* ориентация страницы. } property SectionExtent: Tl3Point read pm_GetSectionExtent write pm_SetSectionExtent; {* размеры текущего раздела с дюймах. } property NotFocused: Boolean write pm_SetNotFocused; property RegionBottomRight: Tl3Point read pm_GetRegionBottomRight; property EffectiveColors: Il3EffectiveColors read Get_EffectiveColors; property PageSetup: Il3PageSetup read pm_GetPageSetup; property Painter: Il3HAFPainter write pm_SetPainter; property Canvas: TCanvas read pm_GetCanvas; property AbortChecker: Il3AbortChecker read Get_AbortChecker write Set_AbortChecker; // Ml3WindowOrg function Get_InitialDCOffset: Tl3Point; function Get_InitialDCOffsetStored: Tl3Point; property InitialDCOffset: Tl3Point read Get_InitialDCOffset; property InitialDCOffsetStored: Tl3Point read Get_InitialDCOffsetStored; // Ml3CanvasState procedure Set_ClipRegion(const aValue: Il3Region); function PushClipRect: Tl3Rect; procedure PopClipRect; property ClipRegion: Il3Region write Set_ClipRegion; // Ml3CanvasInvert function pm_GetInvert: Boolean; procedure BeginInvert; procedure EndInvert; property Invert: Boolean read pm_GetInvert; end;//Il3Canvas
Этот "интерфейс" - НЕВОЗМОЖНО реализовать. БОЛЕЕ одного раза.
Ибо он содержит в себе - МНОЖЕСТВО "побочных знаний".
И "протоколы взаимодействия".
А ЗНАЧИТ - это НЕ ИНТЕРФЕЙС, а "заготовка класса". Пусть и не ЧИСТО абстрактная. Пусть и ЧАСТИЧНО абстрактная.
То что я продемонстрировал выше - это ОДНО из десятков (а то и сотен) ИДИОТСКИХ проектных решений, которые я воплотил в жизнь. Могу продемонстрировать их ВСЕ. С ДЕТАЛЬНЫМ разбором. Был бы только толк.
И кстати - "до конца" проблема станет ясна только под AQTime.
Когда мы УВИДИМ накладные расходы на "подсчёт ссылок". Это уж если про "экономию на спичках".
БЕЗОТНОСИТЕЛЬНО того, что подобные "интерфейсы" в ПРИНЦИПЕ сложно реализовывать.
Или вот ещё:
Ik2Tag = interface(Ik2Base) {* Объект содержащий подъобекты и атомарные атрибуты } ['{2345D08B-36E3-4B6A-ABA8-82C74B3431DF}'] {iterator} function IterateChildrenF(anAction: Ik2Tag_IterateChildrenF_Action; aLo: Tl3Index = l3MinIndex; aHi: Tl3Index = l3MaxIndex; aLoadedOnly: Boolean = false): Integer; {iterator} function IterateChildrenBack(anAction: Ik2Tag_IterateChildrenBack_Action; aHi: Tl3Index = l3MaxIndex; aLo: Tl3Index = l3MinIndex; aLoadedOnly: Boolean = false): Integer; {iterator} function IterateChildrenBackF(anAction: Ik2Tag_IterateChildrenBack_Action; aHi: Tl3Index = l3MaxIndex; aLo: Tl3Index = l3MinIndex; aLoadedOnly: Boolean = false): Integer; {iterator} procedure IterateProperties(anAction: Ik2Tag_IterateProperties_Action; anAll: Boolean {* Перебирать все возможные свойства или только РЕАЛЬНО заданные}); {* перебирает все существующие свойства } {iterator} procedure IteratePropertiesF(anAction: Ik2Tag_IterateProperties_Action; anAll: Boolean {* Перебирать все возможные свойства или только РЕАЛЬНО заданные}); {* перебирает все существующие свойства } function Box: Ik2Tag; {* ссылка на тег - для сохранения. } function IsSame(const aTag: Ik2Tag): Boolean; {* указывает, что инструменты работают с одним и тем же тегом. } procedure CheckSort(aProp: Tk2ArrayPropertyPrim); function AssignTag(const Source: Ik2Tag; AssignMode: Tk2AssignModes = k2_amAll; const Context: Ik2Op = nil): Boolean; function CloneTag: Ik2Tag; procedure AssignCloneParams(const aSource: Ik2Tag; AssignMode: Tk2AssignModes = k2_amAll; const Context: Ik2Op = nil); procedure Write(const G: Ik2TagGenerator; Flags: Tk2StorePropertyFlags = l3_spfAll; Exclude: TByteSet = []); {* записать тег в генератор. } // Mk2Value function pm_GetAsString: AnsiString; function pm_GetAsPCharLen: Tl3PCharLen; function AsBool: Boolean; {* преобразовать к Boolean. } function AsLong: Integer; function AsObject: TObject; property AsString: AnsiString read pm_GetAsString; {* свойство для преобразования к строкам Delphi } property AsPCharLen: Tl3PCharLen read pm_GetAsPCharLen; {* свойство для преобразования к типу Tl3PCharLen } // Mk2TypeInfo function IsOrd: Boolean; function InheritsFrom(anID: Integer): Boolean; overload; {* проверить наследование. } function InheritsFrom(const anIDs: array of Integer): Boolean; overload; {* проверить наследование. } function InheritsFrom(anAtomTypeID: Integer; const Exclude: array of Integer): Boolean; overload; {* проверить наследование. } // Mk2Children function pm_GetChildrenCount: Integer; function pm_GetChild(anIndex: Integer): Ik2Tag; procedure Set_ChildrenCapacity(aValue: Integer); function AddChild(var aChild: Ik2Tag; const aContext: Ik2Op = nil): Integer; {* добавить ребенка. } procedure InsertChild(anIndex: Integer; var aChild: Ik2Tag; const aContext: Ik2Op = nil); {* вставить ребенка. } function IndexOfChild(const aChild: Ik2Tag): Integer; function FindChild(anAtom: Integer; aValue: Integer; const aContext: Ik2Op = nil; aNeedCreate: Boolean = false; theIndex: PLong = nil): Ik2Tag; procedure DeleteChildren(const Context: Ik2Op = nil); {* удалить всех детей. } function DeleteChild(anIndex: Integer; const anOp: Ik2Op; out theChild: Ik2Tag): Boolean; overload; {* удалить ребенка. } function DeleteChild(const aChild: Ik2Tag; const Context: Ik2Op = nil): Boolean; overload; {* удалить ребенка. } function DeleteChild(anIndex: Integer; const anOp: Ik2Op = nil): Boolean; overload; property ChildrenCount: Integer read pm_GetChildrenCount; {* Количество дочерних тегов. } property Child[anIndex: Integer]: Ik2Tag read pm_GetChild; property ChildrenCapacity: Integer write Set_ChildrenCapacity; {* Потенциально возможное число детей } // Mk2RefCount function IntRef: Integer; procedure SetIntRef(out aRef: Integer); // Mk2Storable procedure DoLoad; procedure ForceStore; function MarkModified: Boolean; // Mk2Owned function Get_Owner: Ik2Tag; procedure Set_Owner(const aValue: Ik2Tag); property Owner: Ik2Tag read Get_Owner write Set_Owner; // Mk2IntegerHolder function pm_GetIntA(anIndex: Integer): Integer; procedure pm_SetIntA(anIndex: Integer; aValue: Integer); procedure pm_SetIntW(anIndex: Integer; const aContext: Ik2Op; aValue: Integer); function RLong(anIndex: Integer; aDefault: Integer): Integer; property IntA[anIndex: Integer]: Integer read pm_GetIntA write pm_SetIntA; property IntW[anIndex: Integer; const aContext: Ik2Op]: Integer write pm_SetIntW; // Mk2PCharLenHolder function pm_GetPCharLenA(anIndex: Integer): Tl3PCharLen; procedure pm_SetPCharLenA(anIndex: Integer; const aValue: Tl3PCharLen); procedure pm_SetPCharLenW(anIndex: Integer; const aContext: Ik2Op; const aValue: Tl3WString); property PCharLenA[anIndex: Integer]: Tl3PCharLen read pm_GetPCharLenA write pm_SetPCharLenA; property PCharLenW[anIndex: Integer; const aContext: Ik2Op]: Tl3WString write pm_SetPCharLenW; // Mk2BooleanHolder function pm_GetBoolA(anIndex: Integer): Boolean; procedure pm_SetBoolA(anIndex: Integer; aValue: Boolean); procedure pm_SetBoolW(anIndex: Integer; const aContext: Ik2Op; aValue: Boolean); function RBool(anIndex: Integer; aDefault: Boolean): Boolean; property BoolA[anIndex: Integer]: Boolean read pm_GetBoolA write pm_SetBoolA; property BoolW[anIndex: Integer; const aContext: Ik2Op]: Boolean write pm_SetBoolW; // Mk2StringHolder function pm_GetStrA(anIndex: Integer): AnsiString; procedure pm_SetStrA(anIndex: Integer; const aValue: AnsiString); procedure pm_SetStrW(anIndex: Integer; const aContext: Ik2Op; const aValue: AnsiString); property StrA[anIndex: Integer]: AnsiString read pm_GetStrA write pm_SetStrA; property StrW[anIndex: Integer; const aContext: Ik2Op]: AnsiString write pm_SetStrW; // Mk2ObjectHolder procedure pm_SetObjW(anIndex: Integer; const aContext: Ik2Op; aValue: TObject); property ObjW[anIndex: Integer; const aContext: Ik2Op]: TObject write pm_SetObjW; // Mk2TypeHolder function pm_GetTagType: Tk2TypePrim; property TagType: Tk2TypePrim read pm_GetTagType; // Mk2TagHolder function pm_GetAttr(anIndex: Integer): Ik2Tag; procedure pm_SetAttr(anIndex: Integer; const aValue: Ik2Tag); procedure pm_SetAttrW(anIndex: Integer; const aContext: Ik2Op; const aValue: Ik2Tag); function RAtomEx(const Path: array of Integer; theIndex: PLong = nil): Ik2Tag; {* вернуть подтег. } function ROwnAtom(anIndex: Integer): Ik2Tag; function CAtom(anIndex: Integer; const aContext: Ik2Op = nil; anAtomType: Tk2TypePrim = nil): Ik2Tag; {* проверить существование подтега и создать его при необходимости. } function CAtomEx(const aPath: array of Integer; const aContext: Ik2Op; theIndex: PLong = nil): Ik2Tag; {* проверить существование подтега и создать его при необходимости. } property Attr[anIndex: Integer]: Ik2Tag read pm_GetAttr write pm_SetAttr; default; property AttrW[anIndex: Integer; const aContext: Ik2Op]: Ik2Tag write pm_SetAttrW; // Mk2Compare function CompareWithInt(aValue: Integer; anIndex: Integer): Integer; {* Сравнивает тег с целым. } function CompareWithTag(const aTag: Ik2Tag; aSortIndex: Tl3SortIndex): Integer; // Mk2AtomHolder function HasSubAtom(anIndex: Integer): Boolean; // Mk2TagInfo function IsNull: Boolean; {* пустой тег? } function IsValid: Boolean; {* тег имеет значение? } function IsTransparent: Boolean; {* тег "прозрачный"? } function IsStream(out theStream: IStream): Boolean; {* Проверяет может ли тег приводиться к потоку. И приводит к потоку - если указатель на поток - не нулевой. } // Mk2TagToolProvider function QT(const IID: TGUID; out Obj; const aProcessor: Ik2Processor = nil): Boolean; {* возвращает инструмент для работы с тегом, к которому привязан исходный инструмент. } // Mk2InterfaceProvider function GetOwnInterface(const IID: TGUID; out Obj): Boolean; {* возвращает интерфейс НЕПОСРЕДСТВЕННО поддерживаемый реализацией инструмента. } function GetLinkedInterface(const IID: TGUID; out Obj): Boolean; // Mk2Int64Holder function Get_Int64A(aTagID: Integer): Int64; procedure Set_Int64A(aTagID: Integer; aValue: Int64); procedure Set_Int64W(aTagID: Integer; const aContext: Ik2Op; aValue: Int64); property Int64A[aTagID: Integer]: Int64 read Get_Int64A write Set_Int64A; property Int64W[aTagID: Integer; const aContext: Ik2Op]: Int64 write Set_Int64W; end;//Ik2Tag
Это тоже - УЖАС, а НЕ "интерфейс".
И он к нынешнему моменту - распался на НЕСКОЛЬКО интерфейсов и "примесей".
Комментариев нет:
Отправить комментарий