Mixin(织入)模式并不是GOF的《设计模式》归纳中的一种,但是在各种语言以及框架都会发现该模式(或者思想)的一些应用。简单来说,Mixin是带有全部实现或者部分实现的接口,其主要作用是更好的代码复用。本文将介绍Mixin的应用场景,以及关于继承、组合、多继承、接口的一些思考。
 

相关概念:

  前面提到,Mixin是有部分或者全部实现的接口,其主要作用是代码复用,需要理解这个简单的描述,需要先理清一些概念。

继承与组合:

  继承是面向对象的三大特征(封装、继承、多态),如果类A继承自类B,那么我们称A为子类(派生类),称B为父类(基类)。什么时候类A才能继承类B呢,可以说A是B的一种特殊化,英语来说就是A is a B,或者A is a kind of B。比如狗(dog)和动物(Animal)这两个抽象,dog is animal,这个是成立的,所以dog可以继承自animal。
  而组合代表的是其中一个类的对象是另一个类的对象的组成组合,英语来说,“has a”,比如人(People)这个类有一个属性addr是一个地址类(Address)的实例,就是说每个人都有一个地址。
  不管是继承还是组合,都起到了代码复用的作用,但又各有优缺点。上面继承和组合的例子都很明显,但有些情况就不那么容易区分两类事物是继承还是组合的关系了,或者说,两个类之间既可以用继承,又可以用组合,比如设计模式中的adapter模式,既可以类适配,又可以组合适配(对象适配)。
 

多继承与接口:

  在使用编程语言抽象事物之间的继承关系的时候,需要考虑对多继承的实现。所谓多继承就是说一个类有多个基类,举个简单的例子,dog是animal,同时dog又是runnable(可以跑动的对象)。多继承对于人类的思维来说是比较正常直观的,但是对于计算机编程语言,都会遇到一个绕不过去的问题,那就是菱形继承(diamond problem),下面这个图形象展示了什么时菱形继承:
  
  从上图可以看到,类B、类C都继承了类A,类D同时继承了类B和类C,在继承关系上就形成了“菱形”--类D有两条路径到达类A。菱形问题带来什么问题呢,如果类A定义了某个方法foo,而且B和C都没有重写该方法,那么B和C都会有某种机制找到foo,那么对于D的实例在调用foo方法的时候,是调用到B中指向的foo方法还是C中指向的foo方法呢?
  菱形继承的问题会影响到语言的设计,一些编程语言支持多继承,如C++、python等等;另外一些则不支持多继承,如Java,ruby等。对于支持多继承的语言,为了解决菱形继承的问题,一般都会使用特定的方法,比如C++中的虚继承,python中的新式类的MRO。而对于不支持多继承的语言,一般使用某种接口(或者约定、协议)来实现多继承的功能,如Java中的interface,ruby中的include module。
 

duck typing:

  一个事物是不是鸭子(duck),如果它走起来像一只鸭子、叫起来也像一只鸭子,即从表现来看像一只鸭子,那么我们就认为它是一只鸭子。把这种思想应用到编程中,就是duck typing,简而言之,一个约定要求必须实现某些功能,而某个类实现了这个功能,就可以把这个类当做约定的具体实现来使用。duck typing的思想在编程语言中的使用非常广泛,如Java中的Interface,Python中的各种protocol,ruby中的include module。
  上面提到协议(泛指接口、预定、duck typing,下同)可以用来实现多继承的功能,在以下情况特别合适:“基类”代表的其实是一种能力或者承诺。比如前面dog同时继承animal和runnale,但跑(run)就是一种能力的体现,这个时候就可以把runable作为一个协议,dog是可以跑的,所以应该实现run方法,也就遵循了这个协议,那么dog就是一个runable了。从例子可以看出,如果一个所谓的“基类”事实上代表了某种能力(it can,xxxable)的时候,使用协议比多继承是更佳合理的选择。
 

Mixin:

  在前面说清楚了各个概念之后,我们来看看Mixin到表代表了什么,不过再次回顾上面一段提到的java interface和python protocol,这二者本身是没有任何实现的,都是需要使用者来实现相应的方法。Mixin本身也是一种能力的承诺,但Mixin不同的不同之处在于Mixin是有部分或者全部实现的,在Mixin中的实现有利于代码复用。如果是部分实现,那么就是在Mixin中实现整个流程,而实现Mixin约定的类提供关键的、该类特有的方法,这有点类似模板模式,也是依赖倒置原则的体现。
  不同的语言或者框架中,对Mixin模式有不同的实现形式,python中,除了protocol,也可以用多继承的形式来实现Mixin,为了区分普通的多继承,Mixin类的类名一般都会带上后缀:“Mixin”,比如python lib里面的两个Mixin类:UserDict.DictMixin和SocketServer.ForkingMixIn。DictMixin类包括部分实现,使用者只要实现几个核心的函数接口就行了。
  Mixin defining all dictionary methods for classes that already have a minimum dictionary interface including getitem, setitem, delitem,and keys. 
  而python中的SocketServer.ForkingMixIn有全部的实现,所以使用者无需特殊处理,就拥有了fork带来的好处,例如
  

 class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass
  在python的一些框架中,也有Mixin的身影,如tornado。
  在ruby中,并不直接使用Mixin这个单词,而是使用在类的声明中include 一个module的办法,如下面的代码(来自wiki):
 class Student
include Comparable # The class Student inherits Comparable module using include keyword
attr_accessor :name, :score def initialize(name, score)
@name = name
@score = score
end # Including the Comparison module, requires the implementing class to define the <=> comparison operator
# Here's the comparison operator. We compare 2 student instances based on their scores. def <=>(other)
@score <=> other.score
end end

  首先,include的module叫Comparable (Java中也有一个同名的接口),即可比较的对象,按照之前对协议、约定的讲解,是非常适合使用Mixin模式的。其次,ruby中Comparable这个module也是部分实现,需要具体的类实现<=>方法。


总结:

  Mixin是一种思想,用部分实现的接口来实现代码复用。可以用来解决多继承的问题,又可以用来扩展功能。Mixin在不同的编程语言中又不同的使用形式或者命名,但其本质都是一样的。
 
references:
  
 

什么是Mixin模式:带实现的协议的更多相关文章

  1. Mixin模式:带实现的协议

    Mixin(织入)模式并不是GOF的<设计模式>归纳中的一种,但是在各种语言以及框架都会发现该模式(或者思想)的一些应用.简单来说,Mixin是带有全部实现或者部分实现的接口,其主要作用是 ...

  2. PythonI/O进阶学习笔记_3.2面向对象编程_python的继承(多继承/super/MRO/抽象基类/mixin模式)

    前言: 本篇相关内容分为3篇多态.继承.封装,这篇为第二篇 继承. 本篇内容围绕 python基础教程这段: 在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法.使 ...

  3. 设计模式之Mixin模式

    介绍 mixin模式就是一些提供能够被一个或者一组子类简单继承功能的类,意在重用其功能.在面向对象的语言中,我们会通过接口继承的方式来实现功能的复用.但是在javascript中,我们没办法通过接口继 ...

  4. mixin模式特点

    mixin模式特点: 1.单一功能, 2.不和基类关联,可以和任意基类组合,基类可以不和mixin关联就可以初始化成功 3.不使用 super() 用法

  5. 搭建高可用的redis集群,避免standalone模式带给你的苦难

    现在项目上用redis的话,很少说不用集群的情况,毕竟如果生产上只有一台redis会有极大的风险,比如机器挂掉,或者内存爆掉,就比如我们生产环境 曾今也遭遇到这种情况,导致redis内存不够挂掉的情况 ...

  6. Mixin模式

    Mixin是JavaScript中用的最普遍的模式,几乎所有流行类库都会有Mixin的实现. Mixin是掺合,混合,糅合的意思,即可以就任意一个对象的全部或部分属性拷贝到另一个对象上. 从提供的接口 ...

  7. 【javascript】javascript设计模式mixin模式

    概述: Mixin是JavaScript中用的最普遍的模式,几乎所有流行类库都会有Mixin的实现.任意一个对象的全部或部分属性拷贝到另一个对象上. 一 .混合对象 二 .混合类

  8. Android基础相关面试问题-activity面试问题(生命周期,任务栈,启动模式,跳转协议,启动流程)

    关于Android的一些面试题在15年就已经开了这个专栏了,但是一直木有坚持收集,而每次面对想要跳槽时大脑一片空白,也有些恐惧,因为毕境面试都是纯技术的沟通,要想让公司对你的技术能有所认可会全方位的进 ...

  9. 前端框架中 “类mixin” 模式的思考

    "类 mixin" 指的是 Vue 中的 mixin,Regular 中的 implement 使用 Mixin 的目的 首先我们需要知道为什么会有 mixin 的存在? 为了扩展 ...

随机推荐

  1. Python简单的网络编程

    OSI 模型介绍 应用层 -- 对接受的数据进行解释.加密与解密.压缩与解压缩 会话层 -- 通过传输层(端口号: 传输端口和接受端口) 建立数据传输的通路 传输层 -- 定义了一些传输数据的协议和端 ...

  2. 关于z-index使用方法

    z-index控制的是元素的层叠顺序,当z-index越大此层越靠上:但是z-index需在已给元素定位(定位方式不限)的前提下否则该属性失效!! jquery获取index值的方法: $(" ...

  3. getRealPath函数编译报错问题

    ServletActionContext.getRequest().getRealPath("");函数虽然已被淘汰,但在获取服务器绝对路径时仍有使用.关于 ServletActi ...

  4. 超级干货 :一文读懂数据可视化 ZT

    前言 数据可视化,是指将相对晦涩的的数据通过可视的.交互的方式进行展示,从而形象.直观地表达数据蕴含的信息和规律. 早期的数据可视化作为咨询机构.金融企业的专业工具,其应用领域较为单一,应用形态较为保 ...

  5. loadrunner 运行脚本-Run-time Settings之Pacing设置

    运行脚本-Run-time Settings之Pacing设置 by:授客 QQ:1033553122   As soon as the previous iteration ends 前一个迭代一结 ...

  6. js调用android本地java代码

    js调用android本地java代码 当在Android上使用WebView控件开发一个Web应用时,可以创建一个通过Javascript调用Android端java代码的接口.也就是可以通过Jav ...

  7. vue axios 发送post请求,后端接收参数为null

    1首先检查自己的传参方式是否正确,我是传一个对象,没有问题,接口也触发了 2查了下资料说是 Content-Type的问题,设置为   'application/x-www-form-urlencod ...

  8. linux下zip文件解压乱码的问题

    因为编码问题,zip文件中的中文文件在linux下解压会出现乱码 如果你使用archlinux那么使用AUR安装unzip-natspec就可以解决这个问题 https://aur.archlinux ...

  9. Java动态生成类以及动态添加属性

    有个技术实现需求:动态生成类,其中类中的属性来自参数对象中的全部属性以及来自参数对象properties文件. 那么技术实现支持:使用CGLib代理. 具体的实现步骤: 1.配置Maven文件: &l ...

  10. python装饰器(新年第一写)

    祭奠碌碌无为的2018,想想其实也不算碌碌无为,至少我还搞懂了装饰器,写了一堆有用没用的玩意 原来觉得装饰器挺难的,直到2018年的最后几天,突然就明白了,难道这就是传说中的开天聪么 言归正传,之所以 ...