【问题标题】:Delphi: How to hide ancestor methods?Delphi:如何隐藏祖先方法?
【发布时间】:2011-01-20 16:37:50
【问题描述】:

这是我的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;

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

【问题讨论】:

  • 好吧,你不应该使用 Create,因为它用于构造函数,而这不是构造函数。
  • >>但我认为所有酷孩子都会隐藏他们的物品。
  • @David Heffernan 但 Borland 做到了 :(
  • @Ian 当然,您从 Embarcadero 引用的代码可能是由 typelib 导入器生成的。无论如何,他们并没有试图超载。无论如何,我认为 Create 应该保留给构造函数。
  • 我将这些方法命名为 CreateInstance 并完成它。

标签: delphi inheritance factory factory-pattern


【解决方案1】:

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

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

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

--杰罗恩

【讨论】:

  • 好吧,你可以隐藏祖先方法;只是在您使用overload 时不会。但无法完成的答案很可能是正确的。
  • 因为这些是类方法,所以这个参数不适用。在类函数运行之前没有实例。
  • 确实如此;只需将类引用放在祖先的引用中,就完成了。例如,当Name 是类属性时,TAnimalClass = class of TAnimal; AnimalClass: TAnimalClass; AnimalClass := TNamelessAnimal; Writeln(AnimalClass.Name); 将访问类属性。类方法也一样。
  • @Jeroen 你永远不会写这样的代码。当您使用虚拟构造函数时,您最常使用class of
  • @David et Jeroen:任何利用元类、多态构造函数和虚拟类方法的代码都可以自然而然地完成你的“技巧”。
【解决方案2】:

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

【讨论】:

  • “can simple case”应该是“can simple cast”吧?
  • 因为这些是类方法,所以这个参数不适用。在类函数运行之前没有实例。
  • @David 那又怎样?本身有一个类,可以直接引用。
  • “我不知道是否有任何面向对象的语言支持祖先中的隐藏方法,但我怀疑是否有。” Delphi 支持在祖先中隐藏方法。您只需声明一个具有相同名称的方法,然后,您已经隐藏了一个方法。
  • @David 不,你错了。刚刚在 Delphi 5 中进行了测试 - 投射到祖先成功地击败了后代中具有相同名称的方法的任何技巧。
【解决方案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;

一旦开始使用接口,就很难停下来。

【讨论】:

    【解决方案4】:

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

    干杯

    【讨论】:

      【解决方案5】:

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

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

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

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

      还请注意,您不能减少继承方法的声明可见性...如果继承了“公共”创建方法,那么重新引入“受保护”创建方法实际上不会隐藏完全是公开的。

      【讨论】:

        猜你喜欢
        • 2011-06-07
        • 2013-05-08
        • 2021-08-01
        • 2011-05-29
        • 1970-01-01
        • 1970-01-01
        • 2011-10-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多