Delphi:如何隐藏祖先方法?

时间:2011-01-20 16:37:51

标签: delphi inheritance factory factory-pattern

这是我previous question on how to hide inherited constructors的变体。你如何隐藏继承的方法:

在Delphi允许您构造COM对象的方式之后进行建模:

CoDOMDocument = class
   class function Create: IXMLDOMDocument2;
end;

我有一个工厂,它创建一个实现接口的对象:

CoCondition = class
public
   class function Create: ICondition;
end;

这很好用。虽然在祖先中有一个名为Create的方法,但它工作正常。它有效,因为我没有overload关键字。只要我添加overload关键字:Delphi将允许继承的Create方法“闪耀”:

CoCondition = class
public
   class function Create: ICondition; overload;
end;

现在CoCondition有两种Create方法:

class function CoCondition.Create: ICondition;
constructor TObject.Create;

你要打电话给哪一个是模棱两可的。修复,显然是没有overload关键字(为什么你,你没有重载任何东西?)。好吧,事实证明我超载了一些东西:

CoCondition = class
public
   class function Create: ICondition; overload;
   class function Create(const ConditionType: TConditionType): ICondition; overload;
   class function Create(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant): ICondition; overload;
   class function Create(const ConditionType: TConditionType; const SubConditions: IInterfaceList): ICondition; overload;
end;

由于我有overload个关键字,因此该类有五个重载,而不仅仅是我想要的四个:

class function CoCondition.Create: ICondition;
class function CoCondition.Create(const ConditionType: TConditionType): ICondition; overload;
class function CoCondition.Create(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant): ICondition; overload;
class function CoCondition.Create(const ConditionType: TConditionType; const SubConditions: IInterfaceList): ICondition; overload;
constructor TObject.Create;

我只希望我的四个重载存在,而没有其他。即我想隐藏任何祖先方法。

如何隐藏祖先方法?


我也试着明确地声明祖先方法,但保护它,所以没有人可以得到它:

CoCondition = class
protected
    constructor Create; overload;
public
    class function Create(): ICondition; overload;
    class function Create(const ConditionType: TConditionType): ICondition; overload;
    class function Create(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant): ICondition; overload; //leaf
    class function Create(const ConditionType: TConditionType; const SubConditions: IInterfaceList): ICondition; overload; //AND/OR/NOT children
end;

但由于未加参数的Create()的过度重叠,这无法编译。


我也考虑过:

CoCondition = class
public
   class function Make(): ICondition; overload;
   class function Make(const ConditionType: TConditionType): ICondition; overload;
   class function Make(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant): ICondition; overload; //leaf
   class function Make(const ConditionType: TConditionType; const SubConditions: IInterfaceList): ICondition; overload; //AND/OR/NOT children
end;

但拒绝了它。


我可以公开实现该对象的对象:

TCondition = class(TInterfacedObject, ICondition)
...
public
  constructor Create; overload;
  constructor Create(const ConditionType: TConditionType); overload;
  constructor Create(const PropertyName: string; const Operation: TConditionOperation; const Value: Variant); overload; //leaf
  constructor Create(const ConditionType: TConditionType; const SubConditions: IInterfaceList); overload; //AND/OR/NOT children
end;

但我认为所有酷孩子都隐藏了他们的物品。

5 个答案:

答案 0 :(得分:6)

隐藏方法是不可能的,因为它违背了面向对象编程的基础。

即使一种语言支持隐藏,你也可以随时解决它。

例如,如果您创建具有TAnimal属性的Name类,然后创建一个TNamelessAnimal类,您要隐藏Name属性。
现在,您可以将TNamelessAnimal实例转换为TAnimal引用,并仍然可以访问Name属性。
这是完全符合逻辑的,因为TNamelessAnimalTAnimal,因此具有Name属性。

- 的Jeroen

答案 1 :(得分:4)

Delphi不支持隐藏方法,因为它不符合逻辑。假设祖先TAncestor有公共方法AMethod。现在声明TDescendant = class(TAncestor)并将其覆盖AMethod作为protected。现在,用户可以简单地将您的TDescendant转换为TAncestor并访问应该被隐藏的方法。我不知道任何面向对象的语言是否支持祖先中的隐藏方法,但我怀疑是否存在。

答案 2 :(得分:3)

“隐藏”祖先方法的最佳方法是使用对您而言重要的方法名称声明一个接口...例如:

IMyInterface = interface
  procedure One;
  procedure Two;
end;

然后,在您的类中实现这些方法,将您的类暴露为实现IMyInterface,例如:

TMyClass = class( TInterfacedObject, IMyInterface )
PUBLIC
  procedure One;
  procedure Two;
end;

在代码的其他地方,将类的实例作为IMyInterface(而不是TMyClass)传递。这样可以整齐地隐藏你班级中的所有内部结构,并将你的代码分解成很好的分区模块。

你会惊奇地发现界面声明如何“看起来”像一个类,即具有属性,例如这是合法且非常有用的:

IMyInterface = interface
  function GetSomething : integer;
  procedure SetSomething( AValue : integer );
  property  Something : integer; read GetSomething write SetSomething;
end;

一旦开始使用界面,就很难停止。

答案 3 :(得分:1)

不要费心去争取它。只需将所有实现方法和属性放入其自身单元的受保护范围内,因此它将强制您使用接口。其他选择是使用与param(s)的其他Create方法不同的名称,并删除重载关键字

干杯

答案 4 :(得分:0)

使用“reintroduce”指令标记命名方法的新“版本”:

CoCondition = class
public
   class function Create: ICondition; reintroduce;
end;

这允许您“重新引入”具有不同参数的方法名称。

但请注意,重新引入与重载(虚拟方法)不同...如果使用类引用调用这些方法,则最终调用的Create方法将取决于所涉及的类引用的特定类型,而不是而不是调用“最衍生的版本”。

另请注意,您无法减少声明的继承方法的可见性...如果存在继承的“公共”Create方法,则重新引入“受保护”的Create方法实际上不会隐藏公众一个人。