Clarity in classes implementing multiple interfaces (alternative to delegation):

独自空忆成欢 提交于 2019-12-06 05:00:27

问题


Let's say we've got the following:

IFirst = Interface(IUnknown)    
  function GetStuff: Integer;
end;

ISecond = Interface(IUnknown)
  function GetOtherStuff: Integer;
end;

TFirstSecond = class(TInterfacedObject, IFirst, ISecond)    
private 
  function GetStuff: Integer;        //implementation of IFirst
  function GetOtherStuff: Integer;   //implementation of ISecond;
end;

I have never liked the fact that in TInterfacedObject there seems to be no way to distinguish between which methods implement which interfaces. Am I missing something? Does anyone know a way structure the code to do that? To designate that GetStuff is the implementation of IFirst and GetOtherStuff is the implementation of ISecond? ('Put a comment' is not the answer I'm looking for...)

I know I can use the 'implements' directive to define properties in TFirstSecond for each interface and delegate the implementations to instances contained within TFirstSecond, thereby segregating everything. But I'd like a shortcut...


回答1:


In the case you post, I prefer comments (interface name just as NGLN puts it) too, but I would like to explain why the implements keyword can be the best solution in some other cases, just not in trivial cases where there's only one method per interface as in your trivial sample.

I know you said you know about Implements; but for people coming along who have not seen it, I'd like to document when it IS useful, bear with me. It is even worthwhile having all the extra work of having more classes, in some cases.

So I would use implements not as a shortcut (as you see it's longer!) but only when each interface involves 100 methods to be implemented, and where the resulting design has less coupling, and better cohesion and readability only.

So this is an admittedly silly example, but if each of IFirst and ISecond had 100 methods, then it might be a great leap forward...

type
IFirst = interface
  function GetStuff: Integer;
end;

ISecond = interface
  function GetOtherStuff: Integer;
end;

TFirstLogic = class(TInterfacedObject, IFirst)
  function GetStuff: Integer;

end;

TSecondLogic = class(TInterfacedObject, ISecond)
  function GetOtherStuff: Integer;
end;

TFirstSecond = class(TInterfacedObject, IFirst, ISecond)
private
  FFirst:TFirstLogic;
  FSecond:TSecondLogic;
protected


  property First:TFirstLogic read FFirst implements IFirst;
  property Second:TSecondLogic read FSecond implements ISecond;
public
  constructor Create; // don't forget to create and free FFirst/FSecond.
  destructor Destroy; override; // don't forget to create and free FFirst/FSecond.


end;

You could say Implements is the only way we could do "partial classes", or at least create one composite class that implements a bunch of interfaces, and have a bunch of sub-properties (which are protected or perhaps even private) used to do the "implements" delegation. If you move everything else right out of the unit that contains the aggregating class, you could have a really clean design.




回答2:


I suppose the only thing you can really do without using comments is to add method resolution clauses:

IFirst = interface
  function GetStuff: Integer;
end;

ISecond = interface
  function GetOtherStuff: Integer;
end;

TFirstSecond = class(TInterfacedObject, IFirst, ISecond)
private
  function GetStuff: Integer;
  function GetOtherStuff: Integer;
public
  function IFirst.GetStuff = GetStuff;
  function ISecond.GetOtherStuff = GetOtherStuff;
end;

I don't think this really adds very much to the mix, and I personally would consider this worse than without the method resolution clauses.




回答3:


Although you are specifically asking for an answer not involving comments, may I say that using comments is the common solution by more then just the Delphi VCL, as follows to be precise:

TFirstSecond = class(TInterfacedObject, IFirst, ISecond)
private
  { IFirst }
  function GetStuff: Integer;
private
  { ISecond }
  function GetOtherStuff: Integer;
end;



回答4:


D2006 (but probably earlier versions as well, D2006 is just the earliest I have available at the moment), supports "mapping" of interface methods to specific class functions. This gets rid of the necessity to have a property as you do with the implements keyword.

Using interface mapping should also be a way to remove ambiguity when two interfaces contain the same method signature but need different implementations.

Example:

IMyFirstInterface = interface(IInterface)
  procedure DoSomethingInteresting;
  procedure DoSomethingElse;
end;

IMySecondInterface = interface(IInterface)
  procedure DoSomethingInteresting;
end;

TMyCombinedObject = class(TInterfacedObject, IMyFirstInterface, IMySecondInterface)
private
  // Interface mappings 
  procedure IMyFirstInterface.DoSomethingInteresting = DoSomethingInterestingFirst;
  procedure IMySecondInterface.DoSomethingInteresting = DoSomethingInterestingSecond;
protected
  procedure DoSomethingInterestingFirst;
  procedure DoSomethingInterestingSecond;
  procedure DoSomethingElse;
end;

Drawback if you have lots of interfaces or lots of methods: repetition. However, as you can see in the example, you do not need to specify mappings for all methods in an interface.

For documentation purposes you could put the mapping directly with the actual method declaration, so they stay together and are less likely to get out of sync (or rather that the mappings will miss new methods, as you do not need to declare a mapping for each interface method):

TMyCombinedObject = class(TInterfacedObject, IMyFirstInterface, IMySecondInterface)
protected
  procedure IMyFirstInterface.DoSomethingInteresting = DoSomethingInterestingFirst;
  procedure DoSomethingInterestingFirst;

  procedure IMySecondInterface.DoSomethingInteresting = DoSomethingInterestingSecond;
  procedure DoSomethingInterestingSecond;

  procedure DoSomethingElse;
end;


来源:https://stackoverflow.com/questions/6836425/clarity-in-classes-implementing-multiple-interfaces-alternative-to-delegation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!