我申报会员时可以指定接口吗?
在思考了这个问题一段时间之后,我发现静态鸭式语言可能确实有效.为什么在编译时不能将预定义的类绑定到接口?例:
public interface IMyInterface { public void MyMethod(); } public class MyClass //Does not explicitly implement IMyInterface { public void MyMethod() //But contains a compatible method definition { Console.WriteLine("Hello, world!"); } } ... public void CallMyMethod(IMyInterface m) { m.MyMethod(); } ... MyClass obj = new MyClass(); CallMyMethod(obj); // Automatically recognize that MyClass "fits" // MyInterface, and force a type-cast.
你知道支持这种功能的任何语言吗?它会在Java或C#中有用吗?它在某种程度上存在根本缺陷吗?我知道你可以继承MyClass并实现接口或使用Adapter设计模式来完成同样的事情,但这些方法看似不必要的样板代码.
这个问题的全新答案,Go正是这个功能.我认为这真的很酷很聪明(虽然我很想知道它在现实生活中是如何发挥作用的)并且在思考它时会感到荣幸.
正如官方文档中所述(作为Tour of Go的一部分,带有示例代码):
接口是隐式实现的
类型通过实现其方法来实现接口.没有明确的意图声明,没有"implements"关键字.
隐式接口将接口的定义与其实现分离,然后可以在没有预先安排的情况下出现在任何包中.
在C++中使用模板怎么样?
class IMyInterface // Inheritance from this is optional { public: virtual void MyMethod() = 0; } class MyClass // Does not explicitly implement IMyInterface { public: void MyMethod() // But contains a compatible method definition { std::cout << "Hello, world!" "\n"; } } templatevoid CallMyMethod(MyInterface& m) { m.MyMethod(); // instantiation succeeds iff MyInterface has MyMethod } MyClass obj; CallMyMethod(obj); // Automatically generate code with MyClass as // MyInterface
我实际上并没有编译这段代码,但我相信它是可行的,并且是原始提议(但非工作)代码的一个非常简单的C++化.
我没有看到这一点.为什么不明确该类实现接口并完成它?实现接口是告诉其他程序员该类应该以接口定义的方式运行的原因.简单地在方法上具有相同的名称和签名并不能保证设计者的意图是使用该方法执行类似的操作.这可能是,但为什么要把它留给解释(和误用)?
你能够在动态语言中成功"逃脱"的原因更多地与TDD有关,而不是与语言本身有关.在我看来,如果该语言提供了向使用/查看代码的其他人提供这些指导的工具,那么您应该使用它.它实际上提高了清晰度,值得一些额外的角色.如果您无权执行此操作,则适配器的用途与明确声明接口与其他类的关联方式相同.
根据定义,静态类型语言在编译时检查类型,而不是运行时.上述系统的一个明显问题是编译器将在编译程序时检查类型,而不是在运行时.
现在,您可以在编译器中构建更多智能,以便它可以派生类型,而不是让程序员显式声明类型; 编译器可能会看到MyClass
实现一个MyMethod()
方法,并相应地处理这种情况,而不需要显式声明接口(如你所建议).这样的编译器可以使用类型推断,例如Hindley-Milner.
当然,像Haskell这样的一些静态类型的语言已经做了类似于你的建议; Haskell编译器能够推断类型(大多数时候)而无需显式声明它们.但显然,Java/C#没有这种能力.
F#支持静态鸭子类型,但有一个catch:你必须使用成员约束.此博客条目中提供了详细信息.
引用博客中的示例:
let inline speak (a: ^a) = let x = (^a : (member speak: unit -> string) (a)) printfn "It said: %s" x let y = (^a : (member talk: unit -> string) (a)) printfn "Then it said %s" y type duck() = member x.speak() = "quack" member x.talk() = "quackity quack" type dog() = member x.speak() = "woof" member x.talk() = "arrrr" let x = new duck() let y = new dog() speak x speak y