设计模式
一、设计模式分类
经典的《设计模式》一书归纳出23种设计模式,这23种模式又可归为,创建型、结构型和行为型3大类
1.创建型模式分类
社会化的分工越来越细,自然在软件设计方面也是如此,因此对象的创建和对象的使用分开也就成为了必然趋势。因为对象的创建会消耗掉系统的很多资源,所以单独对对象的创建进行研究,从而能够高效地创建对象就是创建型模式要探讨的问题。这里有6个具体的创建型模式可供研究,它们分别是:
- 简单工厂模式(Simple Factory);
- 工厂方法模式(Factory Method);
- 抽象工厂模式(Abstract Factory);
- 创建者模式(Builder);
- 原型模式(Prototype);
- 单例模式(Singleton)。
- 说明:严格来说,简单工厂模式不是GoF总结出来的23种设计模式之一。
2. 结构型模式分类
在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,因为如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。对象结构的设计很容易体现出设计人员水平的高低,这里有7个具体的结构型模式可供研究,它们分别是:
- 外观模式(Facade);
- 适配器模式(Adapter);
- 代理模式(Proxy);
- 装饰模式(Decorator);
- 桥模式(Bridge);
- 组合模式(Composite);
- 享元模式(Flyweight
3. 行为型模式分类
-
在对象的结构和对象的创建问题都解决了之后,就剩下对象的行为问题了,如果对象的行为设计的好,那么对象的行为就会更清晰,它们之间的协作效率就会提高,这里有11个具体的行为型模式可供研究,它们分别是:
-
模板方法模式(Template Method);
-
观察者模式(Observer);
-
状态模式(State);
-
策略模式(Strategy);
-
职责链模式(Chain of Responsibility);
-
命令模式(Command);
-
访问者模式(Visitor);
-
调停者模式(Mediator);
-
备忘录模式(Memento);
-
迭代器模式(Iterator);
-
解释器模式(Interpreter)
设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:是对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
常用创建型模式实现
工厂模式
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
# 简单工厂
class Shape(object):
def draw(self):
raise NotImplementedError
class Circle(Shape):
def draw(self):
print('draw circle')
class Rectangle(Shape):
def draw(self):
print('draw Rectangle')
class ShapeFactory(object):
def create(self, shape):
if shape == 'Circle':
return Circle()
elif shape == 'Rectangle':
return Rectangle()
else:
return None
fac = ShapeFactory()
obj = fac.create('Circle')
obj.draw()
单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点
#实现__new__方法
#并在将一个类的实例绑定到类变量_instance上,
#如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回
#如果cls._instance不为None,直接返回cls._instance
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'_instance'):
orig = super(Singleton,cls)
cls._instance = orig.__new__(cls)
return cls._instance
class MyClass(Singleton):
def __init__(self,name):
self.name = name
a = MyClass("Alex")
b = MyClass("Jack")
print(a.name)
print(b.name)
建造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
#建造者模式
#相关模式:思路和模板方法模式很像,模板方法是封装算法流程,对某些细节,提供接口由子类修改,建造者模式更为高层一点,将所有细节都交由子类实现。
# 建造者模式:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。
# 基本思想
# 某类产品的构建由很多复杂组件组成;
# 这些组件中的某些细节不同,构建出的产品表象会略有不同;
# 通过一个指挥者按照产品的创建步骤来一步步执行产品的创建;
# 当需要创建不同的产品时,只需要派生一个具体的建造者,重写相应的组件构建方法即可。
def printInfo(info):
print(info)
#建造者基类
class PersonBuilder():
def BuildHead(self):
pass
def BuildBody(self):
pass
def BuildArm(self):
pass
def BuildLeg(self):
pass
#胖子
class PersonFatBuilder(PersonBuilder):
type = '胖子'
def BuildHead(self):
printInfo("构建%s的大。。。。。头" % self.type)
def BuildBody(self):
printInfo("构建%s的身体" % self.type)
def BuildArm(self):
printInfo("构建%s的手" % self.type)
def BuildLeg(self):
printInfo("构建%s的脚" % self.type)
#瘦子
class PersonThinBuilder(PersonBuilder):
type = '瘦子'
def BuildHead(self):
printInfo("构建%s的头" % self.type)
def BuildBody(self):
printInfo("构建%s的身体" % self.type)
def BuildArm(self):
printInfo("构建%s的手" % self.type)
def BuildLeg(self):
printInfo("构建%s的脚" % self.type)
#指挥者
class PersonDirector():
pb = None;
def __init__(self, pb):
self.pb = pb
def CreatePereson(self):
self.pb.BuildHead()
self.pb.BuildBody()
self.pb.BuildArm()
self.pb.BuildLeg()
def clientUI():
pb = PersonThinBuilder()
pd = PersonDirector(pb)
pd.CreatePereson()
pb2 = PersonFatBuilder()
#pd = PersonDirector(pb)
pd.pb = pb2
pd.CreatePereson()
return
if __name__ == '__main__':
clientUI();
模板方法模式
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
class Register(object):
'''用户注册接口'''
def register(self):
pass
def login(self):
pass
def auth(self):
self.register()
self.login()
class RegisterByQQ(Register):
'''qq注册'''
def register(self):
print("---用qq注册-----")
def login(self):
print('----用qq登录-----')
class RegisterByWeiChat(Register):
'''微信注册'''
def register(self):
print("---用微信注册-----")
def login(self):
print('----用微信登录-----')
if __name__ == "__main__":
register1 = RegisterByQQ()
register1.auth()
register2 = RegisterByWeiChat()
register2.auth()
观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
#_*_coding:utf-8_*_
__author__ = 'Alex Li'
#
# 观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式
# 当我们希望一个对象的状态发生变化,那么依赖与它的所有对象都能相应变化(获得通知),那么就可以用到Observer模式, 其中的这些依赖对象就是观察者的对象,那个要发生变化的对象就是所谓’观察者’
class ObserverBase(object):
'''观察者基类''' #放哨者
def __init__(self):
self._observerd_list = [] #被通知对象
def attach(self,observe_subject):
'''
添加要观察的对象
:param observe_subject:
:return:
'''
if observe_subject not in self._observerd_list:
self._observerd_list.append(observe_subject)
print("[%s]已经将[%s]加入观察队列..."%(self.name,observe_subject) )
def detach(self,observe_subject):
'''
解除观察关系
:param observe_subject:
:return:
'''
try:
self._observerd_list.remove(observe_subject)
print("不再观察[%s]" %observe_subject)
except ValueError:
pass
def notify(self):
'''
通知所有被观察者
:return:
'''
for objserver in self._observerd_list:
objserver.update(self)
class Observer(ObserverBase):
'''观察者类'''
def __init__(self,name):
super(Observer,self).__init__()
self.name = name
self._msg = ''
@property
def msg(self):
'''
当前状况
:return:
'''
return self._msg
@msg.setter
def msg(self,content):
self._msg = content
self.notify()
class GCDViewer(object):
'''
共军被观察者
'''
def update(self,observer_subject):
print("共军:收到[%s]消息[%s] "%(observer_subject.name,observer_subject.msg) )
class GMDViewer(object):
'''
国军被观察者
'''
def update(self,observer_subject):
print("国军:收到[%s]消息[%s] "%(observer_subject.name,observer_subject.msg) )
if __name__ == "__main__":
observer1 = Observer("共军放哨者")
observer2 = Observer("国军放哨者")
gongjun1 = GCDViewer()
guojun1 = GMDViewer()
observer1.attach(gongjun1)
observer1.attach(guojun1)
observer2.attach(guojun1)
observer1.msg = "\033[32;1m敌人来了...\033[0m"
observer2.msg ="\033[31;1m前方发现敌人,请紧急撤离,不要告诉共军\033[0m"
————————————————
版权声明:本文为CSDN博主「没有刺的仙人掌」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_21467113/article/details/89480740