禁止现有类的接口实现是否有任何优势?

Ben*_*esh 7 c# oop haskell programming-languages interface

在静态OOP语言中,使用接口来声明几个类共享一些逻辑属性 - 它们是一次性的,可以与a进行比较int,可以序列化等等.

假设.net没有标准IDisposable界面,我刚刚提出了这个美好的想法:

interface IDiscardable { void Discard(); }
Run Code Online (Sandbox Code Playgroud)

我的应用程序使用了很多System.Windows.Forms,我认为这Form满足了成为的一个逻辑要求IDiscardable.问题是,Form在我的项目之外定义,所以C#(和Java,C++...)将不允许我IDiscardable为它实现.C#不允许我正式表示一个Form可以的事实discarded(我可能最终得到一个MyForm包装类或其他东西.

相比之下,Haskelltypeclasses,这是逻辑上类似于接口.甲Show实例可以被呈现(或序列)作为字符串,Eq允许比较等,但有一个重要的不同:你可以写一个类型类实例(类似于实现的界面),而无需访问的类型的源代码.因此,如果Haskell为我提供某种Form类型,Discardable为它编写实例是微不足道的.

我的问题是:从语言设计者的角度来看,第一种方法有什么优势吗?Haskell不是面向对象的语言 - 第二种方法是否OOP以任何方式违反?

谢谢!

Die*_*las 6

这是一个困难的问题,源于一个常见的误解.Haskell类型类(TC)被称为与面向对象编程语言中的接口或抽象类(IAC)"逻辑相似".他们不是.它们代表了关于类型和编程语言的不同概念:IAC是子类型的一种情况,而TC是参数多态的一种形式.

然而,既然你的问题是方法论的,我在这里从方法论的角度回答.从第二个问题开始:

第二种方法[扩展类外实现的方法]是否以任何方式违反OOP

面向对象编程是一组描述程序执行的想法,执行的主要元素,如何在程序代码中指定这些元素,以及如何构造程序以分离不同元素的规范.特别是,OOP基于以下思想:

  • 在其执行的任何状态下,进程(执行程序)由一组对象组成.该集合是动态的:它可以通过对象创建和销毁包含不同状态的不同对象.
  • 每个对象都有一个由一组字段表示的内部状态,这些字段可能包含对其他相关对象的引用.关系是动态的:同一对象的相同字段a可能在不同的状态指向不同的对象.
  • 每个对象都可以从另一个对象接收一些消息.在接收到消息时,对象可以改变其状态并且可以向其字段中的对象发送消息.
  • 每个对象都是一个的实例:该类描述了对象具有哪些字段,它可以接收哪些消息以及接收消息时它所执行的操作.
  • 在对象中a,相同的字段a.f可以在不同的状态指向不同的对象,这些对象可以属于不同的类.因此,a 不需要知道这些对象b属于哪个类; 它只需要知道这些对象接受的消息.因此,这些字段的类型可以是接口.接口声明一组对象可以接收的消息.该类明确指定该类的对象满足哪些接口.

我对这个问题的回答:在我看来是的.

在类外部实现接口(如示例中所示)会破坏以下想法之一:对象的类描述该类中的对象可以接收的完整消息集.

但是,您可能想知道,这是(部分)与AspectJ中的"方面"有关.Aspect描述了几个类中某个"方法"的实现,并且这些实现被包含(编织)到类中.

要回答第一个问题,"第一种方法是否有任何优势",答案也是肯定的:对象的所有行为(它回答的消息)仅在类中的一个地方描述.


Lui*_*las 5

好吧,Haskell方法确实有一个缺点,例如,当您编写两个不同的库时,每个库都为Foo相同的外部类型提供自己的接口实现(由第三个库提供).在这种情况下,现在这两个库不能在同一程序中同时使用.因此,如果你称缺乏劣势是一种优势,那么我认为这对于OOP语言这样做是一个优势 - 但这是一个非常弱的优势.

然而,我要添加的是Haskell类型类有点像OOP接口,但并不完全像它们.但类型类有点像策略和模板方法模式; 可以通过显式传递提供类类操作实现的"字典"对象来模拟类型类.所以下面的Haskell类型类:

class Monoid m where
    mempty :: m
    mappend :: m -> m -> m
Run Code Online (Sandbox Code Playgroud)

...可以使用此显式字典类型进行模拟:

data Monoid_ m = Monoid_ { _mempty :: m, _mappend :: m -> m -> m }
Run Code Online (Sandbox Code Playgroud)

......或像这样的OOP界面:

interface Monoid<M> {
    M empty();
    M append(M a, M b);
}
Run Code Online (Sandbox Code Playgroud)

在此之上添加的类型类是编译器将隐式地维护和传递您的字典.有时在Haskell社区中,您会得到关于何时以及类型类是否优于显式字典传递的参数; 比如Gabriel Gonzalez的"Scrap your type classes"博客文章(请记住,他并不是100%同意他在那里所说的内容!).因此,这个想法的OOP对应的不是扩展语言以允许外部implements声明,仅仅明确使用策略或模板方法有什么缺点?