суббота, 13 декабря 2014 г.

Ссылка. Интерфейсы vs. Абстрактные классы

http://sergeyteplyakov.blogspot.ru/2014/12/interfaces-vs-abstract-classes.html

Для 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

Это тоже - УЖАС, а НЕ "интерфейс".

И он к нынешнему моменту - распался на НЕСКОЛЬКО интерфейсов и "примесей".

Комментариев нет:

Отправить комментарий