在浏览tornado的代码时,auth中的类都以Mixin命名,这个词好奇怪啊,查了一下资料,有人解释Mixin为mix in,混入的意思,类似于多重继承。auth模块实现OpenID和OAuth,为什么要用Mixin方式?Mixin的应用场景?与“接口”概念有什么区别?
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类则同时提供了“规格”和“实现”的多重继承,使用上相比接口会更加简单。