使用接口时,实现类方法是强制返回接口,还是有办法返回对象?
一个例子将澄清:
单位EmployeeIntf中的:
IEmployee = interface(IInterface)
function CoWorker: IEmployee; // We dont know anything about TEmployee here
end;
单位员工:
uses EmployeeIntf;
...
TEmployee = class(TObject, IEmployee)
public
function CoWorker: IEmployee; // Returns an error if set to TEmployee
end;
如果方法返回TEmployee,则当前代码在编译器错误时停止:E2211“CoWorker”声明与接口IEmployee中的声明不同(使用Delphi 2010)
TEmployee.CoWorker方法是强制返回接口,还是有办法返回TEmployee,只要TEmployee是IEmployee?
如果在这种情况下只允许接口,那么OO设计的原因是什么?
[编辑]
正如许多贡献者所要求的,我不需要重新计算TEmployee,并希望将上述问题与任何重新计算的考虑因素区分开来。
这个问题的背景是需要在外部组件(在单独的包中)中使用TEmployee的一组非常有限的公共函数。我不能简单地导入包中的'Employee'单元,因为在使用部分中有太多不依赖的依赖项,所以我正在寻找一种松散耦合的解决方案。
谢谢,
答案 0 :(得分:3)
是强制返回接口的实现类方法吗?
不,但实施被强制匹配接口定义的签名。
有办法返回对象吗?
是的,如果您相应地声明了界面。
type
IEmployee = interface
function CoWorker: TEmployee;
end;
答案 1 :(得分:3)
您可以通过引入方法解析子句来使编译器满意:
type
TEmployee = class(TInterfacedObject, IEmployee)
function IEmployee.CoWorker = IEmployeeCoWorker;
public
function IEmployeeCoWorker: IEmployee;
function CoWorker: TEmployee;
end;
function TEmployee.IEmployeeCoWorker: IEmployee;
begin
result := CoWorker;
end;
当然,这会使代码复杂化,但如果它实际上是你需要的......
答案 2 :(得分:2)
我假设您希望CoWorker
函数返回IEmployee
,以便为此接口的客户端带来好处。
但是,某些时候实现代码有一个访问实现对象的正当理由。当然这样做会产生一种可能不合需要的耦合。
从Delphi 2010开始,您可以使用as
运算符来访问实现对象。
var
EmpIntf: IEmployee;
EmpImp: TEmployee;
...
EmpImp := EmpIntf as TEmployee;
请注意,您现在正在破坏对象的生命周期管理。如果在界面引用变为零后访问EmpImp
,则表示您遇到了麻烦。
最后,我会评论说使用这种方法会有糟糕的设计风格。通常以这种方式找到不是as
的方法更好。
答案 3 :(得分:1)
Delphi不支持covariant return types.所以这与接口无关,而只是对语言本身的限制。
通常这不是问题,因为客户通常应该使用IEmployee
而不应该关心同事的具体类型。您必须提供更多详细信息(可能在新问题中),为什么需要特定类型。
如果你使用接口引用计数,你有更多的理由只使用接口类型引用,因为混合接口和对象引用会搞乱引用计数。
答案 4 :(得分:1)
如果要定义一个返回接口的接口函数,为什么要在实现中返回一个对象?
我相信你只是不知道如何实现“功能CoWorker:IEmployee”。如果这是问题,这是一个简单的解决方案:
TEmployee = class(TInterfacedObject, IEmployee)
public
function CoWorker: IEmployee;
end;
function TEmployee.CoWorker: IEmployee;
begin
Result := TEmployee.Create;
end;
顺便说一下,你应该从TInterfacedObject派生接口实现对象,而不是从TObject派生。
[编辑]
至于你的澄清 - 你不能为TEmployee定义一个小的公共接口,然后从这两个接口派生这个类吗?像这样:
type
IEmployeePublic = ...
IEmployee = ...
TEmployee = class(TInterfacedObject, IEmployee, IEmployeePublic)
function CoWorker: IEmployeePublic;
end;