【问题标题】:When implementing an interface in Delphi, does it matter if the implementation methods are not in the public section?在Delphi中实现接口时,实现方法不在public部分有关系吗?
【发布时间】:2016-05-04 13:58:14
【问题描述】:

给定下面的界面:

ITest = interface ['guidhere']
  procedure TestMethod;
end;

是否有任何理由在实现类中将TestMethod() 声明为public?我已经把它放在privateprotected 部分,它似乎没有什么区别。我只是想知道是否有任何准则,从设计角度(或任何角度),使 public 部分成为 正确 部分来实现该方法。

【问题讨论】:

  • 答案取决于您将如何调用TestMethod;如果仅通过接口引用调用它,则应设为protectedprivate;如果您还允许通过对象引用调用TestMethod,则应设为public

标签: delphi interface


【解决方案1】:

实现方法不在公共部分是否重要?

就编译器而言。没有什么不同的。

话虽如此。私有方法仍然是私有的,即使您可以通过接口访问它们。

unit unit1;
....
IItest = interface
  ['{A3D5FEB6-8E29-4EA8-8DC9-7988294EFA65}']
  procedure Test;
end;

TTest = class(TInterfacedObject, IItest)
private
  procedure Test;
end;

unit unit2;
....
var
  TestT: TTest;
  TestI: ITest;
begin
  TestT:= TTest.Create;
  TestI:= TTest.Create;
  TestT.Test;  //will not compile.
  TestI.Test;  //works.

这样做的原因是该接口只是在其 VMT 中有一个指向方法的指针列表。接口定义中给出了方法的定义。
编译器仅检查签名是否匹配。
它不检查方法的可见性。

根据艾伦的评论,这是一个深思熟虑的设计:

将方法设为私有或受保护将确保您只能通过接口访问它们。这是一种针对对象的预期用途强制执行使用合同的方法。

请注意,这不是错误,甚至不是坏事。
属性也可以“访问”私有方法:

property Items[index: integer] read GetItem write SetItem;  

这里的 GetItem 和 SetItem 通常是私有的。
这会强制您使用该属性访问项目。
使用属性时,实现方法通常受到保护(或更糟:-)。相同的逻辑适用于属性和接口。

对于接口更是如此,因为如果您混合使用接口访问和常规访问,您会遇到引用计数问题。

干净的代码
请注意,您可以在类标题中包含任意数量的可见性部分。
这样,您可以将所有接口方法放在一个部分中,将所有非接口方法放在另一个部分中。

TTest = class(TInterfacedObject, I1, I2)
//I1 methods
private
  ... private I1 methods here...
protected
  .. more I1 methods
//I2 methods
private
  .. some I2 methods
protected
  ..more I2 methods     
//TTest methods
private
  //data members
public
  constructor Create;
  destructor Destroy; override;
end;

这样就可以清楚地知道是什么。

【讨论】:

  • 为什么?这就是封装的全部意义所在。你永远不应该访问一个类的私有部分。如果作者打算让某些东西可以访问,它会受到保护(供后代使用)或公开,供客户使用。
  • 困扰我的是overuseprivate 似乎是默认值,而不是合理的想法。毕竟它应该是OOP。 过度使用 private 会杀死继承模型。自 2006 年以来!我们已经修复了,直到十年后有人认为这是一个错误。如果他们稍后修复一个、两个甚至三个版本,那就更好了。就目前而言,这是对信任的侵犯。我知道组件设计师的感觉正好相反......
  • 使用 private 是一种确保遵循并清楚理解正确继承合同的方法。你所说的“过度使用”,我称之为健康的不愿被锁定在特定实现中。对于您而言,期望班级作者应该“预料到您的特定需求”是最高级别的狂妄自大。类作者只能对类的潜在预期用途进行概括,并且只允许特定类型的扩展。
  • 哦,我明白了。您对编译器修复了助手允许访问私有成员的事实感到不安。好吧,那是一个错误,不应该发生。我什至已经与该功能的原始发明者核实过,它从未打算以这种方式使用。这是封装中的一个漏洞。如果您不想被“强制锁定”,请编写自己的课程。你决定使用另一个作者类,意味着你明白了,疣和所有。
  • 我确实希望您同意允许通过帮助程序对私人成员进行这种级别的“认可”访问显然是一个错误?你依赖它当然是不幸的。除了影响所有助手之外,这比在您使用助手访问技巧时更改内部私有实现的类作者更糟糕吗?
【解决方案2】:

我很欣赏这是一个老问题,但答案不再准确。

我正在使用 Rio,from the documentation:

接口的所有成员都是公共的。不允许使用可见性说明符和存储说明符。 (但可以将数组属性声明为默认值。)

这确实是我观察到的。接口定义不允许指定受保护的、私有的或公共的。


编辑:将 cmets 合并到这个答案中

在撰写本文时,编译器并未对实现接口的方法强制执行任何级别的可见性。这些方法可以通过接口(接口引用)或类(对象实例)调用。

由于接口定义坚持所有方法都是公共的,当通过接口引用调用时,实现方法是公共的,无论它们在实现类中是如何定义的。由于可以从对象中获取对接口的引用,因此可以从对象中调用它们,尽管调用者可能必须先获取接口引用。

鉴于实现方法可以通过接口公开调用,您应该考虑不将它们公开在您的类中会有多大帮助。限制类中方法在接口中公开时的可见性在我看来似乎使代码不那么清晰,但可以提供其他意见!

其中一个 cmets 提到了接口的委托。在我看来,这似乎是一种干扰,因为它只是意味着当对象重新运行接口引用时,它会从委托对象(它本身可以委托接口)返回引用,最终调用的是该对象的方法。

因此,任何实现接口的类都会在通过接口调用时使实现该接口的方法作为公共可用。

【讨论】:

  • 本案没有任何变化。 OP 和answer of Johan 讨论的是实现类 中的可见性,而不是接口成员的可见性。后者总是必须公开的。
  • 感谢 Martin 的评论,但是由于实现类实现了接口(所有方法都必须是公共的),因此不将它们公开是没有意义的。通过接口调用时,接口中的方法都是公共的并且都是可用的。当通过对象调用时,情况可能并非如此,但在我看来,不使可见性相同是无益的。就个人而言,我希望能够使用接口来公开具有受保护访问器的公共属性,但接口不允许这样做。
  • 这对我来说也没有意义。但这是可能的。这就是为什么 OP 询问有关任何指导方针的问题,这些指导方针告诉我们必须在公共部分实施。因此,他指的是实现类而不是接口本身,而您引用的文档链接则如此。
  • 实际上,将实现接口的方法移动到受保护甚至私有的方法是有意义的:如果您不想意外地为对象实例调用它们。我一直这样做。此外,由于接口可以通过委托来实现,因此调用者甚至不能期望方法是实现类的一部分。
  • 嗨@dummzeuch,对于类方法,任何属于接口的部分都可以使用接口指针调用-因此您可以降低可见性,但这完全被接口绕过了。你可以通过委托给一个对象来实现一个接口,但是接口方法仍然对具有接口引用的人是公共的,无论它们在哪里实现。根据上面的评论,OP 是关于实现类的,在委托的情况下是最终委托给的类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-19
  • 2015-01-05
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多