设计模式
一、单例模式
python中的模块是最天然的单例模式
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
单例模式是一种常见的设计模式,在计算机系统中,线程池、缓存、日志对象、对话框、打印机、数据库操作、显卡的驱动程序常被设计成单例。
单例模式分3种:懒汉式单例、饿汉式单例、登记式单例。
单例模式有以下3个特点:
-
只能有一个实例。
-
必须自行创建这个实例。
-
必须给其他对象提供这一实例。
python中的单例
1.1 使用new方法
class SingleTon(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(SingleTon, cls).__new__(cls, *args, **kwargs) return cls._instance class MyCls(SingleTon): a = 1 a = MyCls() b = MyCls() print(id(a), id(b))
1.2 共享属性
创建实例时把所有实例的__dict__指向同一字典,这样他们具有相同的属性和方法
class SingleTon(object): _state = {} def __new__(cls, *args, **kwargs): obj = super(SingleTon, cls).__new__(cls, *args, **kwargs) obj.__dict__ = cls._state return obj class MyCls(SingleTon): a=1
1.3 装饰器版本
def singleTon(cls,*args,**kwargs): instance={} def inner(): if cls not in instance: instance[cls]=cls(*args,**kwargs) return instance[cls] return inner @singleTon class Mycls(object): pass a=Mycls() b=Mycls() print(a is b)
二、工厂模式
工厂模式是我们最常用的实例化对象模式,是用工厂方法代替new操作的一种模式。
使用工厂模式的好处是,如果你想要更改所实例化的类名等,则只需更改该工厂方法内容即可,不需逐一寻找代码中具体实例化的地方(new处)修改了。为系统结构提供灵活的动态扩展机制,减少了耦合。
# 由于python没有抽象类,接口这个概念,要实现抽象类或者接口需要通过abc模块来实现 from abc import abstractclassmethod, ABCMeta class Animal(object): __metaclass__ = ABCMeta @abstractclassmethod def detail(self): pass class Human(Animal): def detail(self): print('这是人类') class Dog(Animal): def detail(self): print('这是狗') class SimpleFactory(object): @staticmethod def createHuman(): return Human() @staticmethod def createDog(): return Dog() SimpleFactory.createDog().detail() SimpleFactory.createHuman().detail()
三、注册模式
注册模式,解决全局共享和交换对象。已经创建好的对象,挂在到某个全局可以使用的数组上,在需要使用的时候,直接从该数组上获取即可。将对象注册到全局的树上。任何地方直接去访问。
# 注册模式 regObj = {} class Register(object): def set(self, cls): regObj[cls] = cls def get(self, cls): return regObj[cls] def unset(self, cls): regObj.pop(cls)
四、策略模式
策略模式是对象的行为模式,用意是对一组算法的封装。动态的选择需要的算法并使用。
策略模式指的是程序中涉及决策控制的一种模式。策略模式功能非常强大,因为这个设计模式本身的核心思想就是面向对象编程的多形性思想。
策略模式的三个角色:
-
抽象策略角色
-
具体策略角色
-
环境角色(对抽象策略角色的引用)
实现步骤:
-
定义抽象角色类(定义好各个实现的共同抽象方法)
-
定义具体策略类(具体实现父类的共同方法)
-
定义环境角色类(私有化申明抽象角色变量,重载构造方法,执行抽象方法)
就在编程领域之外,有许多例子是关于策略模式的。例如:
如果我需要在早晨从家里出发去上班,我可以有几个策略考虑:我可以乘坐地铁,乘坐公交车,走路或其它的途径。每个策略可以得到相同的结果,但是使用了不同的资源。
策略模式的代码实例:
# 策略模式 # 由于python没有抽象类,接口这个概念,要实现抽象类或者接口需要通过abc模块来实现 from abc import abstractclassmethod, ABCMeta # 我们定义一个聚会的抽象类,然后再唱歌、吃饭策略 class Gather(object): __metaclass__=ABCMeta @abstractclassmethod def haveFun(self): pass class Sing(Gather): def haveFun(self): print('唱歌') class Eat(Gather): def haveFun(self): print('吃饭') class Strategy(object): @staticmethod def selectWay(flag): if flag: return Sing() else: return Eat() Strategy.selectWay(True).haveFun()
五、观察者模式
-
观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象全部会收到通知,并自动更新。
-
场景:一个事件发生后,要执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理的逻辑。当更新的逻辑增多之后,代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件的主体代码。
-
观察者模式实现了低耦合,非侵入式的通知与更新机制。 定义一个事件触发抽象类。
# 观察者模式 class Observer(object): def __init__(self): self._observers = [] # 添加观察者 def attach(self, obs): if obs not in self._observers: self._observers.append(obs) # 取消添加观察者 def detach(self, obs): if obs in self._observers: self._observers.remove(obs) # 通知观察者数据变化 def notify(self, modifier=None): for obs in self._observers: if modifier != obs: obs.update(self) class Data(Observer): def __init__(self, name=''): super(Data, self).__init__() self.name = name self._data = 0 @property def data(self): return self._data @data.setter def data(self, value): self._data = value self.notify() # 这里有2个被观察者,也就是依赖的对象,每次Data有改变,这2个view都会变动 class HexViewer(object): def update(self, subject): print('HexViewer: Subject %s has data 0x%x' % (subject.name, subject.data)) class DecimalViewer(object): def update(self, subject): print('DecimalViewer: Subject %s has data %d' % (subject.name, subject.data)) if __name__ == '__main__': data1 = Data('Data 1') data2 = Data('Data 2') view1 = DecimalViewer() view2 = HexViewer() data1.attach(view1) data1.attach(view2) data2.attach(view2) data2.attach(view1) print ("Setting Data 1 = 10") data1.data = 10 print ("Setting Data 2 = 15") data2.data = 15 print ("Setting Data 1 = 3") data1.data = 3 print ("Setting Data 2 = 5") data2.data = 5 print ("Update data1's view2 Because view1 is be filtered") data1.notify(modifier=view1) print ("Detach HexViewer from data1 and data2.") data1.detach(view2) data2.detach(view2) print ("Setting Data 1 = 10") data1.data = 10 print ("Setting Data 2 = 15") data2.data = 15