`
ooaer
  • 浏览: 137481 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Mixin and Trait

阅读更多
  对于Mixin(混合)、Trait(特性)这两个面向对象特性,总是让人觉得说不清道不明的感觉,其实众多设计语言里,这里面的一些概念也是相互参杂的,并不是又那么一个严格的定义或界限说哪种一定是Mixin,或者哪种一定是Trait。这两种语言设施的提出,它的本质实际上都是解决代码复用的问题。下面我们局一些例子来说明。介于本人的认识有限,在此也只是说说自己的看法。
 
多继承 VS 单继承

引用
The developers of the Java language were well-versed in C++ and other languages that include multiple inheritance, whereby classes can inherit from an arbitrary number of parents. One of the problems with multiple inheritance is that it's impossible to determine which parent inherited functionality is derived from. This problem is called the diamond problem (see Resources). The diamond problem and other complexities that are inherent in multiple inheritance inspired the Java language designers to opt for single inheritance plus interfaces.

Interfaces define semantics but not behavior. They work well for defining method signatures and data abstractions, and all of the Java.next languages support Java interfaces with no essential changes. However, some cross-cutting concerns don't fit into a single-inheritance-plus-interfaces model.

在Java 中,一个类可以实现任意数量的接口。这个模型在声明一个类实现多个抽象的时候非常有用。不幸的是,它也有一个主要缺点。对于许多接口,大多数功能都可以用对于所有使用这个接口的类都有效的“样板”代码来实现。Java 没有提供一个内置机制来定义和使用这些可重用代码。相反的,Java 程序员必须使用一个特别的转换来重用一个已知接口的实现。在最坏的情况下,程序员必须复制粘贴同样的代码到不同的类中去。

Mixin VS Trait

  本人认为这两个的涵义根据语言不同,而解释有所不同。但是它们的目的都是作为单继承不足的一种补充,或者是变相地实现多继承。实际上Java的接口也是变相的实现多继承,但是java的接口只是定义signature,没有实现体。在某种意义上Mixin和Trait这两者有点类似于抽象类,或者是有部分或全部实现体的Interface,但是在具体语言中,有表现出不一样的用法。总体上,笔者认为没有特别固定的或者是严格的区别。Mixin和Trait这两者都不能生成实例,否则就跟class没什么区别了。下面分别这两者的例子:

Scala trait
class Person ; //实验用的空类

trait TTeacher extends Person {  

    def teach //虚方法,没有实现  

}  
trait TPianoPlayer extends Person {  

    def playPiano = {println("I’m playing piano. ")} //实方法,已实现  

}  
class PianoplayingTeacher extends Person with TTeacher with TPianoPlayer {  

    def teach = {println("I’m teaching students. ")} //定义虚方法的实现  

} 

PHP traits
  // the template
trait TSingleton {
  private static $_instance = null;
 
  public static function getInstance() {
    if (null === self::$_instance)
    {
      self::$_instance = new self();
    }
 
    return self::$_instance;
  }
}
class FrontController {
  use TSingleton;
}
// can also be used in already extended classes
class WebSite extends SomeClass {
  use TSingleton;
}


Ruby mixin
module Foo
  def bar
    puts "foo";
  end
end

然后我们把这个模块混入到对象中去:
class Demo
  include Foo
end 

如上编码后,模块中的实例方法就会被混入到对象中:
d=Demo.new
d.bar

勉强的区别
从上面看来,从使用上来说,可能看不出什么区别,但是如果说非要说区别的话,笔者通过搜索摘录和归纳了一些区别:
1)Mixin可能更多的是指动态语言,它是在执行到某个点的时候,将代码插入到其中来达到代码复用的效果。Trait更多的是编译过程中,通过一些静态手段赋值代码到类中使得其拥有Trait中的一些功能以达到代码复用的目的;
2)“Mixins may contain state, (traditional) traits don't.”这个区别比较弱,事实上Scala中Trait已经可以保存状态了(成员变量);
3)“Mixins use "implicit conflict resolution", traits use "explicit conflict resolution"”。这个区别可能是个明显的区别;但是如果某个语言它可以让Trait implicit resolve,那也没什么大不了。
4)“Mixins depends on linearization, traits are flattened.”这个区别可能有。至少Scala里面貌似Trait是Flattened处理的,跟Java嵌套类差不多。

下面是程序设计中,是该用类还是Mixin&Trait:
引用
类还是Trait?
当我们考虑是否一个“概念”应该成为一个Trait 或者一个类的时候,记住作为混入的Trait 对于“附属”行为来说最有意义。如果你发现某一个Trait 经常作为其它类的父类来用,导致子类会有像父Trait 那样的行为,那么考虑把它定义为一个类吧,让这段逻辑关系更加清晰。(我们说像。。。的行为,而不是是。。。,因为前者是继承更精确的定义,基于Liskov Substitution Principle -- 例如参见 [Martin2003]。)


参考链接:
http://www.ibm.com/developerworks/java/library/j-jn8/index.html
http://stackoverflow.com/questions/925609/mixins-vs-traits
http://en.wikipedia.org/wiki/Trait_(computer_programming)
http://developer.51cto.com/art/200909/150722.htm
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics