如果我在基类上实现一个接口,它将由它的子类继承,我知道函数/过程将是,但我更感兴趣的是我是否能够将子类强制转换为接口然后返回到它原班.
我希望我能做的是将不同基类的对象传递给一个函数,然后在函数确定中输入并根据需要使用它们.
这是可能的,这是正确的方法吗?
更新
为了帮助消除任何混乱(或创造更多),我想做的事情(条纹下到核心).
接口
IMyInterFace = interface ['{B7203E50-F5CB-4755-9DB1-FB41B7B192C5}'] function MyFunction: Boolean; end;
基类
type TMyObject = class(TInterfacedObject,IMyInterFace)
子类
type TSubMyObject = class(TMyObject)
另一类
type TMyOtherObject = class(TInterfacedObject,IMyInterFace)
然后用法
procedure foo(); var obj:TSubMyObject; begin obj := TSubMyObject.Create(); SendInterfaceObject(obj); end; procedure bar(); var obj:TMyOtherObject; begin obj := TMyOtherObject.Create(); SendInterfaceObject(obj); end; procedure SendInterfaceObject(iobj:IMyInterFace); begin if (iobj is TSubMyObject) then begin //code here end else if (iobj is TMyOtherObject) then begin //code here end; end;
更新2
我更新了代码abit,以便更好地展示我的意思.
//这里的代码部分与传递给它的对象几乎没有关系,例如,如果这个类是TAccounts并且它被传递了一个TEmployee对象,那么它可以支付每周付费,但是如果它是TInvoice那么它会检查到看看是否需要支付,只在日期是死线前2天支付.
TEmployee/TInvoice甚至可能来自要求付款的外派.
这只是一个例子.
是的,接口由子类继承.
从子类转换到接口是完全可以接受的.
但是,如果我错误地阅读你的问题,并且如果"然后回到原来的班级"就意味着道歉...
你有接口I,A类和B类.一个实现I,B继承A,你可能,但是真的不应该从A转换为B.
编辑:
你想从B到I再回到B. ..但是你已经有了对B的引用,如果B是你传递给你的函数的,那么你不需要从I转换为B(除非是在讨论不同的对象,否则不要这样做)
从I到B的过程与从A到B的过程相同,你试图建立继承链,这是你不应该做的事情.需要这样做是一个代码气味,它告诉你,你应该尝试以不同的方式解决这个问题(可能通过重新设计你的类(例如向我添加更多的属性/方法),或者只是决定该函数只能工作使用子类 - 使用子类'B'将允许您访问A&I的所有方法.
您可以编辑您的问题并添加一些您尝试做的示例代码吗?
编辑2
procedure SendInterfaceObject(iobj:IMyInterFace); begin if (iobj is TSubMyObject) then begin //code here end; end;
那里的'If'语句是个坏主意,并打破了OO主体.如果你需要这样做,那么
接口定义不足,您可能希望向接口添加一个Type属性,允许您(如果iObj.SomeProperty = 1)...)
接口根本不是解决此问题的正确解决方案,您应该将引用作为TSubMyObject传递.
编辑3:
@mghie:我同意你的观点,我没有解释得很好,SomeProperty有一些数据允许函数在那里分支,消除了类型检查的依赖性.SomeProperty不应该"简单地"替换类型检查(例如,通过将类名放在属性中,然后检查类名)这确实是完全相同的问题.
继承接口的子类之间存在一些本质区别.这种差异应该由两者表示
公开一些可以在brach中使用的数据项
例如
if(item.Color = Red) then item.ContrastColor := Blue; else item.ContrastColor := Red;
或者通过多态性,例如
IEmployee定义了一个CalculatePay方法,TManager和TWorker实现了IEmployee,每个方法在CalculatePay方法中都有不同的逻辑.
如果意图是像第一种情况那样做,那么多态可能是过度的(多态性并不能解决所有问题).
编辑4
你说"这里的//代码部分与传递给它的对象几乎没有关系......" 我很抱歉,但是这个说法是不正确的,如果你需要支付一个员工,你需要知道他们的1)EmployeeCode 2)他们的工资细节3)他们的银行详细信息等,如果你需要收取发票,你需要1)InvoiceNumber 2)发票金额3)CustomerCode收取等费用...这是多态性的理想场所.
让我们说接受界面的功能检查"账户"是否需要对对象做一些事情(例如,支付员工,收取发票等).所以我们可以调用AccountCheck函数.在内部账户检查中,您将拥有特定于每个子类的逻辑(支付员工,收取发票......)这是多态性的理想候选者.
在您的界面上(或在另一个界面上,或作为子类上的虚方法)定义"AccountsCheck"方法.然后每个派生类都有自己的Accounts check实现.
代码移出你的单个AccountsCheck函数,并转移到每个子类的较小函数中.这使得代码
意图更明显(每个类包含一些AccountCheck的逻辑)
在AccountsCheck for C中修改内容时,你不太可能破坏SubClass B的逻辑
更容易弄清楚SubClass B的AccountsCheck逻辑究竟是什么,你只需要检查小型AccountsCheck中的20行代码,而不是通用AccountsCheck中的200行代码.
还有更多,"很好的理由",如果有人想编辑/发表评论,请这样做.
如果您发现需要在AccountsCheck的实现之间共享一些逻辑,请创建一些实用程序函数,不要在每个实现函数中重新实现相同的轮.
多态性是解决您问题的方法.