预备知识:php
开放封闭原则(Open-Closed Principle OCP)java
Software entities(classes,modules,functions etc) should open for extension ,but close for modification.python
所谓开放封闭原则就是软件实体应该对扩展开放,而对修改封闭。开放封闭原则是全部面向对象原则的核心。c++
软件设计自己所追求的目标就是封装变化,下降耦合,而开放封闭原则正是对这一目标的最直接体现。程序员
对扩展开放,意味着有新的需求或变化时,能够对现有代码进行扩展,以适应新的状况。算法
对修改封闭,意味着类一旦设计完成,就能够独立其工做,而不要对类尽任何修改。c#
以上,是抄得。设计模式
ok, 故事开始。函数
从去年开始,咱们公司搞起了O2O开放平台。提供了O2O各个语言版本的基础库,好比c# php java python等.测试
随着时间的推移,接入开放平台的企业愈来愈多,使用各类语言的版本。
那么,咱们写代码模拟这个过程。
写以前,介绍一下python的“属性”。
为何要介绍这个东西,由于我以前是个c#程序猿,用得最多的就是这货。
在绑定属性时,若是咱们直接把属性暴露出去,虽然写起来很简单,可是,没办法检查参数,致使能够把成绩随便改:
s = Student() s.score = 9999
这显然不合逻辑。为了限制score的范围,能够经过一个set_score()
方法来设置成绩,再经过一个get_score()
来获取成绩,这样,在set_score()
方法里,就能够检查参数:
class Student(object): def get_score(self): return self._score def set_score(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value
如今,对任意的Student实例进行操做,就不能为所欲为地设置score了:
>>> s = Student() >>> s.set_score(60) # ok! >>> s.get_score() 60 >>> s.set_score(9999) Traceback (most recent call last): ... ValueError: score must between 0 ~ 100!
可是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。
有没有既能检查参数,又能够用相似属性这样简单的方式来访问类的变量呢?对于追求完美的Python程序员来讲,这是必需要作到的!
还记得装饰器(decorator)能够给函数动态加上功能吗?对于类的方法,装饰器同样起做用。Python内置的@property
装饰器就是负责把一个方法变成属性调用的:
class Student(object): @property def score(self): return self._score @score.setter def score(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value
就是这么好用(固然,比起c#来讲,仍是有点丑陋,为何我就不说了..毕竟php是世界上最好的语言)
ok,如今开始开放平台的接入工做。因而咱们写了以下代码:
>>> s = Student() >>> s.score = 60 # OK,实际转化为s.set_score(60) >>> s.score # OK,实际转化为s.get_score() 60 >>> s.score = 9999 Traceback (most recent call last): ... ValueError: score must between 0 ~ 100!
# -*- coding: utf-8 -*-
class OpenService(object): @property def language(self): return self.__language @language.setter def language(self, value): self.__language = value def __init__(self): self.__language = 'csharp' def attack_cities(self): if self.__language == 'python': print '攻城师 苦逼兮兮, 写python' elif self.__language == 'java': print '攻城师 苦逼兮兮, 写java' elif self.__language == 'php': print '攻城师 屌屌的, 写php,毕竟php是世界上最好的语言' elif self.__language == 'c#': print '攻城师 苦逼兮兮, 写c#' if __name__ == "__main__": open_service = OpenService() print '某公司1开始对接python...' open_service.language = 'python' open_service.attack_cities() print '某公司2开始对接java...' open_service.language = 'java' open_service.attack_cities() print '某公司3开始对接php...' open_service.language = 'php' open_service.attack_cities() print '某公司4开始对接c#...' open_service.language = 'c#' open_service.attack_cities()
PM一声令下,公司1,2,3,4 纷纷对接开放平台.

过了一段时间,触宝又增长了,c++,c,vb.....等各类语言的开放平台sdk...
那么怎么办呢?很简单..在attack_cities 方法里加更多的if else 判读呗...
因而代码的坏味道出现了....
1. 过长的if else 是明显的坏味道..
2. 写代码是个复杂的过程,所有写在一个方法里...这个方法明显职责太重.违背了本文一开始的单一职责原则。
是时候重构了,当当当当,静态工厂模式善良登场。

ok,上面也是我抄得。
知道了定义,咱们就要对咱们的场景作出抽象。变化的部分是语言,以及攻城狮如何攻城。那么咱们就须要设计一个语言基类。带有攻城的抽象方法。
而后须要定义一个工厂,根据不一样的需求产出不一样的语言攻城狮。
固然,为了使用抽象方法,咱们必须引入卫生巾模块abc
这样的话,子类若是不实现基类的抽象方法,会抛出not implement 异常(我猜是这个异常)
以下:
import abc
class OpenServiceFactory(object): languageInstance = None def __init__(self): pass @staticmethod def CreateLanguage(language): if language == 'c#': OpenServiceFactory.languageInstance = CsharpLanguage() elif language == 'java': OpenServiceFactory.languageInstance = JavaLanguage() elif language == 'php': OpenServiceFactory.languageInstance = PHPLanguage() elif language == 'python': OpenServiceFactory.languageInstance = PythonLanguage() return OpenServiceFactory.languageInstance class LanageBase(object): @abc.abstractmethod def att_cities(self): pass class CsharpLanguage(LanageBase): def att_cities(self): print '攻城师 苦逼兮兮, 写c#' class JavaLanguage(LanageBase): def att_cities(self): print '攻城师 苦逼兮兮, 写java' class PHPLanguage(LanageBase): def att_cities(self): print '攻城师 屌屌的, 写php,毕竟php是世界上最好的语言' class PythonLanguage(LanageBase): def att_cities(self): print '攻城师 苦逼兮兮, 写python'
测试:
if __name__ == "__main__": print '简单工厂思密达' print '某公司1开始对接python...' open_service = OpenServiceFactory.CreateLanguage('python') open_service.att_cities() print '某公司2开始对接java...' open_service = OpenServiceFactory.CreateLanguage('java') open_service.att_cities() print '某公司3开始对接php...' open_service = OpenServiceFactory.CreateLanguage('php') open_service.att_cities() print '某公司4开始对接c#...' open_service = OpenServiceFactory.CreateLanguage('c#') open_service.att_cities()
运行:
➜ static_factory python static_factory.py
某公司1开始对接python...
攻城师 苦逼兮兮, 写python
某公司2开始对接java...
攻城师 苦逼兮兮, 写java
某公司3开始对接php...
攻城师 屌屌的, 写php,毕竟php是世界上最好的语言
某公司4开始对接c#...
攻城师 苦逼兮兮, 写c#
简单工厂思密达
某公司1开始对接python...
攻城师 苦逼兮兮, 写python
某公司2开始对接java...
攻城师 苦逼兮兮, 写java
某公司3开始对接php...
攻城师 屌屌的, 写php,毕竟php是世界上最好的语言
某公司4开始对接c#...
攻城师 苦逼兮兮, 写c#
➜ static_factory
结论: 简单工厂模式并无消除工厂类的条件判断
当有需求扩展时候,必须修改工厂类,违背了了本文一开始提出的开放封闭原则
因此,这不是一个完美的模式,因而有人把简单工厂开除出了设计模式。
真是的。其实人家也是有很多优势的。
1. 减小耦合,子类单独实现算法
2. 客户端调用时,只需关心工厂类,减小复杂度
3. 工厂封装和抽象了变化的部分,经过工厂来实现了子类的建立,子类经过多态实现基类方法.
以上,简单工厂模式,但愿对您有所帮助。。
to be continued