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
Это тоже - УЖАС, а НЕ "интерфейс".
И он к нынешнему моменту - распался на НЕСКОЛЬКО интерфейсов и "примесей".
Комментариев нет:
Отправить комментарий