【Python】Python 用mixin模式让程序更加灵活

Python 用mixin模式让程序更加灵活

在理解mixin之前,有必要先重温一下模板方法模式。所谓的模板方法模式就是在一个方法中定义一个算法的骨架,并将一些实现步骤延迟到子类中。模板方法可以使子类在不改变算法结构的情况下,重新定义算法中的某些步骤。在这里,算法也可以理解为行为。 模板方法模式在C++或其他语言中并无不妥,但是在Python语言中,则颇有点画蛇添 足的味道。比如模板方法,需要先定义一个基类,而实现行为的某些步骤则必须在其子类中,在Python中并无必要。

class People(object):
def make_tea(self):
teapot = self.get_teapot()
teapot.put_in_tea()
teapot.put_in_water()
return teapot
在这个例子中,get_teapot()方法并不需要预先定义。假设在上班时,使用的是简易茶壶, 而在家里,使用的是功夫茶壶,那么可以这样编写代码:

class OfficePeople(People):
def get_teapot(self):
return SimpleTeapot()
class HomePeople(People):
def get_teapot(self):
return KungfuTeapot()
这段代码工作得很好.虽然看起来像模板方法,但是基类并不需要预先声明抽象方法, 甚至还带来调试代码的便利。假定存在一个People的子类StreetPeople,用以描述“正走在 街上的人”,作为“没有人会随身携带荼壶”的常识的反映,这个类将不会实现get_teapot()方法,所以一跑用make_tea()就会产生一个找不到get_teapot()方法的AttributeError。由此 程序员马上会想到“正走在街上的人”边走边泡茶这样的需求是不合理的,从而能够在更高 层次上考虑业务的合理性,在更接近本源的地方修正错误。 但是.这段代码并不完美。老板(OfficePeople的一个实例)拥有巨大的办公室,他购置 了功夫茶具,他要在办公室喝功夫茶了。怎么办?答案有两种,一种是从OfficePeople继承 子类Boss,里写它的get_teapot(),使它返回功夫茶具;另一个则是把get_teapot()方法提取 出来,把它以多继承的方式做一次静态混人。

class UseSimpleTeapot(object):
def get_teapot(self):
return SimpleTeapot()
class UseKungfuTeapot(object):
def get_teapot(self):
return KungfuTeapot ()
class OfficePeople (People, UseSimpleTeapot) :pass
class HomePeople(People, UseKungfuTeapot):pass
class Boss(People, UseKungfuTeapot):pass
这样就很好地解决了老板在办公室也要喝功夫茶的需求。但是这样的代码仍然没有把 Python的动态性表现出来:当新的需求出现时,需要更改类定义。比如随着公司扩张,越 来越多的人人职,OfficePeople的需求越来越多,开始出现有人不喝茶而是喝咖啡,也有人 既喜欢喝茶还喜欢喝咖啡,出现了喜欢在独立办公室抽雪茄的职业经理人……这些类越来越 多,代码越发难以维护。让我们开始寄望于动态地生成不同的实例。

def simple_tea_people():
people = People()
people.bases += (UseSimpleTeapot,)
return people
def coffee_people():
people = People()
people.base += (UseCoffeepot,)
return people
def tea_and_coffee_people():
people = People()
people.bases += (UseSimpleTeapot, UseCoffeepot,)
return people
def boss():
people = People()
people.bases += (KungfuTeapot, UseCoffeepot,)
return people
这个代码能够运行的原理是,每个类都有一个__bases__属性,它是一个元组,用来存 放所有的基类a与其他静态语言不同,Python语言中的基类在运行中可以动态改变。所以当 我们向其中增加新的基类时,这个类就拥有了新的方法,也就是所谓的混人(mixin)。这种 动态性的好处在于代码获得了更丰富的扩展功能。想象一下,你之前写好的代码并不需要个 性,只要后期为它增加基类,就能够增强功能(或替换原有行为).这多么方便!值得进一步 探索的是,利用反射技术,甚至不需要修改代码。假定我们在0A系统里定义员工的时候, 有一个特性选择页面,在里面可以勾选该员工的需求。比如对于Boss,可以勾选功夫茶和咖 啡,那么通过的代码可能如下:

!pip3 install mixins
Looking in indexes: https://pypi.douban.com/simple
Collecting mixins
/usr/share/python-wheels/urllib3-1.24.1-py2.py3-none-any.whl/urllib3/connectionpool.py:849: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
Downloading https://pypi.doubanio.com/packages/0b/0e/d47a96f3c8c4185b4e1b18342c1b989948ac81735e9a7ebde930ec96675e/mixins-0.1.1.tar.gz
Building wheels for collected packages: mixins
Running setup.py bdist_wheel for mixins … [?25ldone
[?25h Stored in directory: /home/yubiao/.cache/pip/wheels/a8/e0/0c/daf93eb5bbdafe0ea33c6fa2d407e60c7148ff83bf7369ec63
Successfully built mixins
Installing collected packages: mixins
Successfully installed mixins-0.1.1
import mixins

def staff():
people = People()
bases =[]
for i in config.checked():
bases,append(getattr(mixins,i))
people.bases += tuple(basest)
return people
看,通过这个框架代码,OA系统的开发人员只需要把员工常见的需求定义成Mixin预 告放在mixins模块中,就可以在不修改代码的情况下通过管理界面满足几乎所有需求了 Python的动态性优势也在这个例子中得到了很好的展现。

你可能感兴趣的:(Python,技术研发,项目管理,python)