python设计模式六大原则
一.单一职责原则(SRP:Single responsibility principle)
一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。例如,搓衣板,既可以用来跪,也可以用来洗衣服。而在单一职责原理下,搓衣板的两个功能就是引起这个类变化的两个原因,就应该写成两个类
""" 单一职责原则 """
class Person(object):
""" 人类 """
def duty(self, one):
""" Coder 的职责是写代码 ,农民就负责斗地主,其余的学习 """
return one is "Coder" and "Coding" or one is "Farmer" and "Chinese poker" or "Studying"
if __name__ == '__main__':
p = Person()
print(p.duty("Coder"))
此时如果细分责任到每一个人,岂不是一堆的判断,肯定不科学,所以尽量让一个类或者一个模块做一件事
""" 单一职责原则 """
class Person(object):
""" 人类 """
def duty(self, one):
""" Coder 的职责是写代码 ,农民就负责斗地主,其余的学习 """
return one is "Coder" and "Coding" or one is "Farmer" and "Chinese poker" or "Studying"
class Coder(Person):
""" 农民 """
def duty(self):
""" Coder 的职责是写代码 """
return "Coding"
class Farmer(Person):
""" 程序员 """
def duty(self):
""" 农民就负责斗地主 """
return "Chinese poker"
if __name__ == '__main__':
c = Coder()
print(c.duty())
f = Farmer()
print(f.duty())
二. 里氏替换原则( LSP:Liskov Substitution Principle)
任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为
- 子类必须完全实现父类的抽象方法,但不能覆盖父类的非抽象方法
- 子类可以实现自己特有的方法
- 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格
- 子类的实例可以替代任何父类的实例,但反之不成立
# -*- coding: utf-8 -*-
import abc
import time
""" 里氏替换原则 """
HOUR = 3600
class Person(object):
""" 人类 """
@abc.abstractmethod
def duty(self):
""" 职责 """
pass
class Coder(Person):
""" 程序员 """
def duty(self):
""" Coder 的职责是写代码 """
return "Coding"
def sleep(self):
""" 有时睡5小时 """
time.sleep(5*HOUR)
class Farmer(Person):
""" 程序员 """
def duty(self):
""" 农民就负责斗地主 """
return "Chinese poker"
def sleep(self):
""" 农民可以睡八小时 """
time.sleep(8*HOUR)
三. 接口隔离原则(ISP)
接口隔离原则表明客户端不应该被强迫实现一些他们不会使用的接口,应该把胖接口中的方法分组,然后用多个接口代替他,每一个接口服务与一个子模块(与单一职责原则有类似的思想)
- 一个类对另一个类的依赖性应当是建立在最小的接口上的。ISP还可以降低各个客户端之间的依赖性(低耦合)。
- 客户端程序不应该依赖它不需要的接口方法,这就要求对接口进行细化,保证其纯洁性
通过使用接口隔离原则,本实例重构后的结构如图2所示
四. 开放-封闭原则(OCP)
实现开放-封闭原则的核心思想是对抽象编程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,这样的修改是封闭的;而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现新的拓展方法,所以对于拓展是开放的。
- 在设计方面充分利用“抽象”和“封装”思想。
一方面是要在软件系统中找出各种可能的“可变因素”并将之封装起来 - 在系统功能编程实现方面应用面向接口编程。
当需求变化时,可以提供该接口新的实现类,以适应需求变化。
"""
开放封闭原则
"""
import abc
"""定义一个抽象的接口(接口是开放的)"""
class Process(metaclass=abc.ABCMeta):
@abc.abstractmethod
def process(self):
"""必须实现一个功能"""
pass
"""实现对接口的拓展"""
"""解码功能"""
class Playerencode(Process):
def process(self):
return "encoding..."
"""输出流功能"""
class Playeroutput(Process):
def process(self):
return "ouputing..."
"""定义线程调度管理类"""
class PlayProcess(object):
def __init__(self):
self.message = None
"""判断某个对象或类是否继承于某个类"""
def ischildof(self,obj, cls):
try:
for i in obj.__bases__:
if i is cls or isinstance(i, cls):
return True
for i in obj.__bases__:
if self.ischildof(i, cls):
return True
except AttributeError: #当是对象时捕获的异常
return self.ischildof(obj.__class__, cls)
return False
def callback(self,event):
self.message = event.click()
if self.ischildof(self.message,Process):
return self.message.process()
"""实现一个MP4产品(产品功能是封闭的)"""
class Mp4(object):
def work(self):
playProcessOjb = PlayProcess()
print(playProcessOjb.callback(Event("encode")))
print(playProcessOjb.callback(Event("output")))
"""工厂类"""
class Event(object):
def __init__(self,msg):
self.__m = msg
def click(self):
if self.__m == "encode":
return Playerencode()
elif self.__m == "output":
return Playeroutput()
mp4 = Mp4()
mp4.work()
五. 依赖倒置原则(DIP)
每个接口中不存在子类用不到却必须实现的方法,如果不然就要将接口拆分,使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个接口)。
- 上层模块不应该依赖于下层模块,它们共同依赖于一个抽象类(父类不能依赖子类,它们都要依赖抽象类)
- 抽象不能依赖具体,具体应该要依赖于抽象
- 子类应该依赖于“抽象”而不应该依赖于某个实体对象
六. 迪米特法则(LoD)
低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。低耦合的优点不言而喻,要做到低耦合,正是迪米特法则要去完成的。