Oop 检查类是否在运行时实现接口

Oop 检查类是否在运行时实现接口,oop,language-agnostic,Oop,Language Agnostic,假设FrameworkA使用FrameworkA.StandardLogger类进行日志记录。我想用另一个日志库(SuperLoggerclass)替换日志库 为了实现这一点,有接口:FrameworkA将提供其他库必须实现的FrameworkA.Logger接口 但是如果其他库没有实现该接口呢FrameworkA可能是一个不够流行的框架,不足以让SuperLogger关心它的接口 可能的解决办法是: 具有标准化的接口(由JSR、PSR等标准定义) 写适配器 如果没有标准化的接口,并且您希望

假设
FrameworkA
使用
FrameworkA.StandardLogger
类进行日志记录。我想用另一个日志库(SuperLogger
class)替换日志库

为了实现这一点,有接口
FrameworkA
将提供其他库必须实现的
FrameworkA.Logger
接口

但是如果其他库没有实现该接口呢
FrameworkA
可能是一个不够流行的框架,不足以让
SuperLogger
关心它的接口

可能的解决办法是:

  • 具有标准化的接口(由JSR、PSR等标准定义)
  • 写适配器
如果没有标准化的接口,并且您希望避免在类兼容的情况下编写无用适配器的痛苦,该怎么办

难道不能有另一种解决方案来确保类在运行时符合约定吗?

想象一下(非常简单的伪代码实现):

SupperLogger
Logger
兼容,只要它实现了Logger接口。但与其对
FrameworkA.Logger
具有“硬依赖性”,不如在运行时验证其公共“接口”(或签名):

// Something verify that SupperLogger implements Logger at run-time
Logger logger = new SupperLogger();

// setLogger() expect Logger, all works
myFrameworkAConfiguration.setLogger(logger);
在假场景中,如果类与接口不兼容,我希望Logger=new SupperLogger()
在运行时失败,但如果类与接口不兼容,则成功


这在OOP中是否有效?如果是,它是否以任何语言存在?如果否,为什么无效?

我的问题代表静态类型语言(Java,…)或动态类型语言(PHP,…)


对于PHP&al:我知道在没有类型检查的情况下,您可以使用任何想要的对象,即使它没有实现接口,但我对实际检查对象是否符合接口的内容感兴趣。

这被称为duck typing,这是一个在Ruby中可以找到的概念(“它像鸭子一样走路,它像鸭子一样呱呱叫,它一定是鸭子”)


在其他动态类型的语言中,您可以模拟它,例如在PHP中,使用
方法\u exists
。在静态类型的语言中,可能存在使用反射的变通方法,即搜索“duck typing+language”“将有助于找到它们。

这更像是一个静态类型的问题,而不是OOP问题。Java和Ruby都是OO语言,但Java不允许您想要什么(静态类型),而Ruby允许您想要什么(动态类型)

从静态类型语言的角度来看,一个主要的优势(如果不是主要的话)是在编译时知道赋值是否安全有效。您所寻找的是由动态类型语言(如Ruby)提供的,但在静态类型语言中是不可能的,这是通过设计实现的(编译时安全性)

您可以,但这很难看,可以(在Java中)执行以下操作:

这将在编译时通过,但如果赋值无效,则会在运行时失败

也就是说,上面的内容非常难看,我不会这么做——它不会给你太多,并且在运行时可能会出现令人不快(可能令人惊讶)的异常

我想,在Java这样的语言中,最好的方法是将创建从您想要使用它的地方抽象出来:

Logger logger = getLogger();

使用
getLogger
的内部组件决定返回什么。然而,这只是将实际的创建推迟到下一步—您仍然必须以静态类型的安全方式进行操作。

只需补充一点,.Net将允许您这样做,尽管它是静态类型的,并带有一些巧妙的反射—但您在很大程度上放弃了静态类型的好处,而没有获得动态类型的好处打字有趣-我得看一下:-)啊,谢谢你创造了这个词!但是我说的是更严格的“duck类型”:如果对象与接口不兼容,则失败。问题是,动态类型语言不允许您定义“接口”,或者如果它们这样做了,则会变成静态类型,而您不能进行duck类型(例如,PHP有时可以是静态类型)。所以最终,静态类型将不允许它,而动态类型将允许任何东西。我想允许任何与接口兼容的东西,我也在寻找这种类型系统的语言,但我想你指的是编译时,而不是运行时,因为对于运行时,你几乎可以为任何语言编写代码,检查方法的可用性和签名,如果它们不匹配,则抛出异常。
Object objLogger = new SupperLogger();
Logger logger = (Logger)objLogger;
Logger logger = getLogger();