回复内容:
Mixin 实质上是利用语言特性(比如 Ruby 的 include 语法、Python 的多重继承)来更简洁地实现组合模式 。
以如下 Java 伪码为例,实现一个可复用的“打标签”组件(Taggable),并且应用到帖子(Post)模型上:
import java.util.List ; import java.util.ArrayList ; interface Entity { public int getId (); public int getKind (); } interface Taggable { public void addTag ( int tagId ); public List Integer > getTags (); } class TaggableImpl implements Taggable { private Entity target ; public TaggableImpl ( Entity target ) { this . target = target ; } public void addTag ( int tagId ) { int id = target . getId (); int kind = target . getKind (); System . out . println ( "insert into ... values " + id + ", " + kind + ", " + tagId + ")" ); } public ArrayList Integer > getTags () { // query from database return new ArrayList Integer >(); } } class Post implements Entity , Taggable { public final static int KIND = 1001 ; private Taggable taggable ; private int id ; private String title ; public Post ( int id , String title ) { this . id = id ; this . title = title ; this . taggable = new TaggableImpl ( this ); } public int getId () { return id ; } public int getKind () { return KIND ; } public void addTag ( int tagId ) { taggable . addTag ( tagId ); // delegate } public ArrayList Integer > getTags () { return taggable . getTags (); // delegate } }Mixin 就是混入的意思。
和多重继承类似(其实可以把 Mixin 看作多重继承的一种在特定场景下的应用),但通常混入 Mixin 的类和 Mixin 类本身不是 is-a 的关系,混入 Mixin 类是为了添加某些(可选的)功能。自由地混入 Mixin 类就可以灵活地为被混入的类添加不同的功能。
传统的「接口」概念中并不包含实现,而 Mixin 包含实现。实际上 Mixin 的作用和 Java 中的众多以「 able 」结尾的接口很相似。不同的是 Mixin 提供了(默认)实现,而 Java 中实现了 -able 接口的类需要类自身来实现这些混入的功能(Serializable 接口是个例外)。 趁着午休来答一个。
如楼上很多答主一样,谈到Mixin就不得不谈到多重继承,因为Mixin的出现就是为了解决多重继承的问题,那么多重继承有什么问题呢?
在《松本行弘的程序世界》一书中,作者列举了以下三点:
结构复杂化:如果是单一继承,一个类的父类是什么,父类的父类是什么,都很明确,因为只有单一的继承关系,然而如果是多重继承的话,一个类有多个父类,这些父类又有自己的父类,那么类之间的关系就很复杂了。 优先顺序模糊:假如我有A,C类同时继承了基类,B类继承了A类,然后D类又同时继承了B和C类,所以D类继承父类的方法的顺序应该是D、B、A、C还是D、B、C、A,或者是其他的顺序,很不明确。 功能冲突:因为多重继承有多个父类,所以当不同的父类中有相同的方法是就会产生冲突。如果B类和C类同时又有相同的方法时,D继承的是哪个方法就不明确了,因为存在两种可能性。 当然你可以说有些语言解决了这个问题,但是并不是所有语言都想要去纠结这个问题。
所以为能够利用多继承的优点又解决多继承的问题,提出了规格继承和实现继承这两样东西。
简单来讲,规格继承指的是一堆方法名的集合,而实现继承除了方法名还允许有方法的实现。
Java 选择了规格继承,在 Java 中叫 interface(不过Java8中已经有默认方法了),而 Ruby 选择了实现继承,也可以叫Mixin,在 Ruby 中叫 module。
从某种程度上来说,继承强调 I am,Mixin 强调 I can。当你 implement 了这个接口或者 include 这个 module 的时候,然后就你行你上。
所以这又可以扯到 duck typing 去了,不细说。要想了解具体的可以看一下《松本行弘的程序世界》这本书。 这叫迷信方法,你想知道好处,打开py源码,搜搜 mixin,试着不用迷信实现一个本来用了迷信的模块,就能切身感受一下了。 为了解决多重继承的问题,Java引入了接口 (interface) 技术, Lisp、Ruby引入了 Mix-in 技术。
以 Ruby 为例,Mix-in 有效地降低多重继承复杂性(谁是你爹,哪个爹的优先级高,你的把妹方法 是继承自哪个爹的等)。 Ruby中 Mix-in 的单位是 模块 (module) 。
Mix-in 技术按一下规则来限制多重继承:
继承用但一继承; 第二个及两个以上的父类必须是 Mix-in 的抽象类。
Mix-in 类是具有以下特征的抽象类:
不能单独生成实例; 不能继承普通类。
按照以上的原则,类在层次上具有单一继承一样的树结构,同时又可以实现功能的共享(方法是:把共享的功能放在 Mix-in 类中,再把 Mix-in 类插入到树结构里)。
Java 用 接口 解决规格继承 (类都有哪些方法)的问题,Mix-in 则解决了实现继承 (类中都用了什么数据结构和什么算法)的问题。
逼逼了这么多,对于 Mix-in 的理解是, Mix-in 只不过是实现多重继承的一个技巧而已。 被约束的多重继承。 mixin不是多继承,mixin是duck type的糖,让你可以不用去把一坨坨Interface继承一遍然后才能彼此调用接口。 mixin 并没有特别权威的标准,非要让我下个定论的话:mixin 其实就是在语言不提供标准多重继承的情况下,变相实现多重继承的一个语法糖。 不同版本的 mixin 实现不太一样,但出发点都是在允许继承接口和继承实现的基础上,简化继承关系,避免多重继承的坑。
我认为 C# 的扩展方法其实就是一种 mixin,但又不是通过代码拷贝等动态特性实现的,而是在编译器层面很严格的帮你进行了封装。对其它静态语言来说,如果没有多重继承,要自己实现 mixin 是很困难的。动态语言有些就支持 mixin,不支持的话自己造一个也很容易。
我最近也利用 javascript 实现了一个版本的 mixin 机制,为了支持可视化编辑,添加了类似组件系统的能力,将整合进 0.5 的 Fireball-x,到时会进一步更新答案。
手机码字求赞,欢迎更多讨论。 就是编译的时候把一段代码复制到另一个地方的意思。 Mixin是一种特殊的多重继承,也就是多重继承的子集。
使用Mixin的好处是,同时享有单一继承的单纯性和多重继承的共有性。
作为Mixin类,需要满足以下条件:
不能单独生成实例对象,属于抽象类。 不能继承Mixin以外的类。 因为有以上限制,Mixin类通常作为功能模块使用,在需要该功能时“混入”,而且不会使类的关系变得复杂(比如,同名方法到底从哪个父类继承)。
Java的接口,只提供了“规格”的多重继承。Mixin类则同时提供了“规格”和“实现”的多重继承,使用上相比接口会更加简单。
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did89919