[python] Mixin 扫盲班

原创 2007年06月18日 20:35:00
 
Mixin 扫盲班
赖勇浩(http://blog.csdn.net/lanphaday)
 
声明:本文适合初中级Python程序员阅读,另外本文措词可能会导致阅读者不适,敬请PG。
 
引子
嗯,为什么要谈Mixin啊?
因为出现了Mixin这样一个东西呀,就像C++社区很多人谈论template一样啊,Python社区也很多会谈论Mixin的(以后会的,嘻嘻),所以我就来凑凑热闹了。
 
嗯,为什么要Mixin呀?
这个,基本上已经是我这篇文章里要讲的东西了,所以,我会用本文的大部分篇幅来回答你这个超有深度的问题。现在,就开始吧~
 
小时候,我家开百货店,当然,也兼营水果蔬菜啊。
小时候的事,总是特别有趣,也特别的有意义,所以今天我们就以水果店开始吧~
 
记得,以前很多人买水果的时候,都会问我妈一个问题,就是价格了啦~但还有两个问题也经常问到哦,就是送人应该买什么水果和什么水果可以用来送人?
 
嗯,年青人大多都不懂这些礼节。送水果也是很讲兆头的,比如梨和香蕉一般不用来送人,因为它们意味着离别和焦躁哦;而苹果和桔子就很受欢迎,因为它们意味着平安和吉利哦~
以此为开始
那,这跟Python有什么关系吗?
当然有啦,不然我扯那么多皮干嘛咧?现在,国产凌凌漆接到一个任务,要求他为一个水果连锁店开发一套软件;显然这个不关心国计民生这些鸡毛蒜皮的小事的武夫是搞不定这项艰巨任务的了,他就找到了你。
 
通过调研,客户发现两件事实:一是现在的年青人还是不懂送人应该买什么水果和什么水果可以用来送人这两个问题;二是水果连锁店的营业员100%都是年青人,他们也不懂。
所以,客户决定在软件中必须提供一个这样的功能--可以查询一种水果是否适宜送人。
最初,你可能这样设计:
class Fruit(object):
       pass
把fruit类作为一切水果的基类,嗯,这相当明智。代码中去除了一些无需关注的代码,如价格、产地等。
现在你打算实现最受顾客欢迎的苹果:
class Apple(Fruit):
       def is_gift_fruit(self):
              return True
同样的,我又去除了一些无需关注的代码,并且打算在接下来的行文中不再提醒这一点。
Apple is a fruit。所以上面的实现挺符合OO的原则。
接下来让我们实现梨子吧:
class Pear(Fruit):
       def is_gift_fruit(self):
              return False
解决问题了。如果水果连锁店只卖苹果和梨子两种水果的话。
可惜,需求很多,你还要实现桔子和香蕉呢。你写下了这几行代码:
class Orange(Fruit):
       def is_gift_fruit(self):
              return True
class Banana(Fruit):
       def is_gift_fruit(self):
              return False
好臭啊,代码的坏味道!
类apple和类Orange除了类名不同,几乎是完全重复的代码;类Pear和类Banana也是一样。
更进一层的说,这四个类都差不多啊,所以我们有必要重构一下已有代码,改善它们的设计。
改善已有代码
阅读代码,你可以发现水果只分两类:一类是可以作为礼品的,一类是不可以的。所以希望可以这样设计:
              Fruit
              /      /
       GiftFruit NotGiftFruit
       /      /      /      /
Apple        Orange Pear    Banana
嗯,加了两个中间类,看起来不错:
class GiftFruit(Fruit):
       def is_gift_fruit(self):
              return True
class NotGiftFruit(Fruit):
       def is_gift_fruit(self):
              return False
class Apple(GiftFruit):pass
class Orange(GiftFruit):pass
class Pear(NotGiftFruit):pass
class Banana(NotGiftFruit):pass
好啦,看上去很不错哦,代码精简了不少,任务完成~
新的烦恼
接下来我们来完成另一项功能:提供水果食用方法咨询。
不要笑这个需求,这是真实的市场需求。比如相当部分一辈子生活在北方的朋友就没有吃过龙眼荔枝香蕉;而南方虽然水果丰富,但不知道山竹等洋水果的也大有人在。我们这个水果连锁店业务简单,水果的食用方法也只分两种:一种是剥皮的,如桔子和香蕉;另一种是削皮的,如苹果和梨子。让我们修改原有的设计:
                     Fruit
                     /      /
              GiftFruit NotGiftFruit
              /      /      /             /
       PareG...   HuskG...     PareNot...     HuskNot...
       /             /      /             /     
Apple           Orange        Pear              Banana
不得已,我们添加了四个类:
class PareGiftFruit(GiftFruit):
       def eat_method(self):
              return 'Pare'
class HustGiftFruit(GiftFruit):
       def eat_method(self):
              return 'Husk'
class PareNotGiftFruit(NotGiftFruit):
       def eat_method(self):
              return 'Pare'
class HuskNotGiftFruit(NotGiftFruit):
       def eat_method(self):
              return 'Husk'
怎么这四个类这么像啊?汗。。。。
先忍忍,把AOPB四种水果的实现改改:
class Apple(PareGiftFruit):pass
class Orange(HuskGiftFruit):pass
class Pear(PareNotGiftFruit):Pass
class Banana(HuskNotGiftFruit):pass
我已经忍无可忍了。这个设计不仅仅又引入了好不容易消除的重复代码,而且还修改了AOPB这四个类的实现。这种设计的扩展性也不好,如果以后要提供水果的其它特点,比如是进口水果还是国产水果。天啊,这还了得!加上这个特性,我要实现LocalPareGiftFruit、LocalHuskGiftFruit等类共8个(2的三次方)啊。水果的特征多得很,随便算算可能超过16种啊,65536个类?叫我去死吧~单是长达16个单词的类名我就崩溃了!
现在,你们都应该意识到这种实现方法实在是一种龌龊的设计了。那,我们应该怎么样设计呢?
Pythonic的方案
该是Mixin出场的时候了!
先来看看Mixin的实现吧:
class Fruit(object):
       pass
class GiftMixin(object):
       def is_gift_fruit(self):
              return True
class NotGiftMixin(object):
       def is_gift_fruit(self):
              return False
class PareMixin(object):
       def eat_method(self):
              return 'Pare'
class HuskMixin(object):
       def eat_method(self):
              return 'Husk'
class Apple(GiftMixin, PareMixin, Fruit):pass
class Orange(GiftMixin, HuskMixin, Fruit):pass
class Pear(NotGiftMixin, PareMixin, Fruit):pass
class Banana(NotGiftMixin, HuskMixin, Fruit):pass
编码完成!这就是Mixin,就是这么简单,以致我无法再说出任何言语,因为我觉得上面的代码已经完整地表达了我想要表达的思想。
Mixin的好处是可以为主类(如Fruit)添加任意多的Mixin来实现多态,比如刚才说的水果有进口和国产两个特征,现在相当容易实现:
class NativeMixin(object):
       def Locality(self):
              return 'Native'
class ForeignMixin(object):
       def Locality(self):
              return 'Foreign'
class Apple(ForeignMixin, GiftMixin, PareMixin, Fruit):pass #进口红富士
class Orange(NativeMixin, GiftMixin, HuskMixin, Fruit):pass
class Pear(NativeMixin, NotGiftMixin, PareMixin, Fruit):pass
class Banana(NativeMixin, NotGiftMixin, HuskMixin, Fruit):pass
简单多了,只加了两个类,对AOPB的实现也只是增加了一个基类(增加总是胜过修改)。
利用Mixin我们还可以增加无数总特征,而无需对已有代码作太大改动。
除此之外
这时候,你可能会说:水果连锁店软件只是你杜撰的一个项目,Mixin有什么实际用处吗?当然有啦!其实Mixin并不是什么高阶的Python技巧,早有就很多开源项目使用这个技巧了,典型的,比如Python项目啊!在Python自带的SimpleServer.py里就应用了Mixin来实现基于进程和基于线程的两种TCP/UDP服务模型,在Tkinter和Python的其它模块也可以见到它的踪迹,如果你留意的话。
确切来说,我对Mixin来实现的水果连锁店的实现仍然相当不满意,但如果我们想要足够面向对象,也就基本上只能接受如此解决方案了。如果有一天你不能忍受每增加一种特征你就必须编写N(N>=2)个Mixin,然后都必须给已经存在的AOPB代码增加一个基类(想想,水果店卖的可不止四种水果,你会更头大),那,就考虑把OO抛弃吧!
鸣谢
在本文成文过程中,沈崴(http://eishn.blog.163.com)给我很大帮助,特此鸣谢。
 
版权声明:本文为博主原创文章,未经博主允许不得转载。

【Python基础】Python面向对象 - 7 - Mixin & MRO

转自:http://xiaocong.github.io/blog/2012/06/13/python-mixin-and-mro/ 什么是 mixin ? In obje...
  • robinjwong
  • robinjwong
  • 2015年09月11日 17:46
  • 872

Django 进阶(装饰器,Mixin,信号,模式)

抽象models类class BaseProfile(models.Model): USER_TYPES = ( (0, 'Ordinary'), (1, 'S...
  • tmpbook
  • tmpbook
  • 2016年05月30日 19:47
  • 3375

JavaScript-mixin实现多继承

mixin简单通俗的讲就是把一个对象的方法和属性拷贝到另一个对象上,注意这个继承还是有区别的。js是一种只支持单继承的语言,毕竟一个对象只有一个原型,如果想实现多继承,那就简单暴力的把需要继承的父类的...
  • qiqingjin
  • qiqingjin
  • 2016年06月26日 13:30
  • 5280

什么是Mixin模式:带实现的协议

Mixin(织入)模式并不是GOF的《设计模式》归纳中的一种,但是在各种语言以及框架都会发现该模式(或者思想)的一些应用。简单来说,Mixin是带有全部实现或者部分实现的接口,其主要作用是更好的代码复...
  • dapangzi88
  • dapangzi88
  • 2017年03月04日 13:51
  • 632

学习Python:Mix-in技术介绍

Mix-in技术介绍 原文地址:http://wiki.woodpecker.org.cn/moin/IntroMixin Mixin可以译为混入,就是在不改变原对象的情况下对其进行扩展。本文介绍了...
  • dotadage
  • dotadage
  • 2014年12月17日 18:29
  • 978

React学习之扩展PureRenderMixin(三十三)

PureRenderMixin的出现早于React.PureComponent,该插件属于历史保留,现在就使用React.PureComponent吧,这里也就提一下如果你的React组件的渲染函数是...
  • qq_18661257
  • qq_18661257
  • 2017年04月02日 09:42
  • 2292

设计模式--Mixin模式

Adapter模式:把一个接口转换为另一个接口。 Decorator模式:给一个对象动态增加功能。比如Java的 new BufferedOutputStream(new FileOutputS...
  • xuhx
  • xuhx
  • 2011年09月09日 15:27
  • 6164

Python3学习(25)--多继承之mix-in("混入")技术

前面,我们学习过OOP的继承,知道子类可以继承父类的特性,可以拿来用,也可以改变父类的特性变为已有,当然,我们只是学习了一种继承关系,今天,我们要重新认识一下Python的继承之 多继承 ...
  • Appleyk
  • Appleyk
  • 2017年09月08日 09:01
  • 3201

Java的mixin模式说明

java语法规定只能使用单继承,避免多继承带来的麻烦,但是多继承也有自己的优点。而mixin模式可以使java拥有多重继承。 继承是面向对象编程的一个重要的方式,因为通过继承,子类就可以扩展父类的功...
  • u012263493
  • u012263493
  • 2015年09月10日 22:09
  • 1391

Django类视图与Mixin

在上一篇Django处理http请求流程剖析中,笔者详细地说明了Django框架是如何根据WSGI协议处理一个Http请求的。其中,处理开发者自行定义的View的代码如下:# django.core....
  • laughing2333
  • laughing2333
  • 2016年12月31日 23:56
  • 1618
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[python] Mixin 扫盲班
举报原因:
原因补充:

(最多只允许输入30个字)