三种最基本的设计模式:
- 创建模式,提供实例化的方法,为适合的状况提供相应的对象创建方法。
- 结构化模式,通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。
- 行为模式,用于在不同的实体建进行通信,为实体之间的通信提供更容易,更灵活的通信方法。
设计模式的六大原则
- 开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
- 里氏(Liskov)替换原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象。
- 依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
- 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
- 迪米特法则:一个软件实体应当尽可能少地与其他实体发生相互作用。
- 单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
创建型模式
- 单例模式
单例模式(Singleton Pattern)目的是确保某一个类只有一个实例存在。
实现单例有多种方法:装饰器,_new_, metaClass, import
每一个python模块都是天生的单例模式
### 单例模式
class Singleton(object):
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = object.__new__(cls)
return cls._instance
ob_1 = Singleton()
ob_2 = Singleton()
print(id(ob_1), id(ob_2))
- 工厂模式
当以下情形可以使用工厂模式:
1.不知道用户想要创建什么样的对象
2.当你想要创建一个可扩展的关联在创建类与支持创建对象的类之间。
工厂模式有很多种实现类型,下面只介绍一种工厂方法模式
### 工厂模式
class Person:
def __init__(self):
self.name = None
self.gender = None
def getName(self):
return self.name
def getGender(self):
return self.gender
class Male(Person):
def __init__(self, name):
super().__init__()
print(f'Mr.{name}')
class Female(Person):
def __init__(self, name):
super().__init__()
print(f"Miss.{name}")
class PersonFactory:
@staticmethod
def getPerson(name, gender):
if gender == "M":
return Male(name)
if gender == "F":
return Female(name)
ob_1 = PersonFactory.getPerson("big", "M")
ob_2 = PersonFactory.getPerson("bigTwo", "F")
- 原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
浅拷贝(Shallow Copy):指对象的字段被拷贝,而字段引用的对象不会被拷贝,拷贝的对象和源对象只是名称相同,但是他们共用一个实体。
深拷贝(deep copy):对对象实例中字段引用的对象也进行拷贝。
### 原型模式
import copy
class Book:
def __init__(self, *args, **kwargs):
self.__dict__.update(kwargs)
def __str__(self):
return str(sorted(self.__dict__.items()))
class ProtoType:
def __init__(self):
self.objects = dict()
def register(self, nid, obj):
self.objects[nid] = obj
def unregister(self, nid):
del self.objects[nid]
def clone(self, nid, **attr):
found = self.objects.get(nid)
if not found:
raise ValueError(f"{nid} No exist")
obj = copy.deepcopy(found)
obj.__dict__.update(attr)
return obj
b_1 = Book("aaa", k="kkk", b="bbb")
prototype = ProtoType()
prototype.register("b_1", b_1)
b_2 = prototype.clone("b_1", e="eee", d="ddd")
print(b_1)
print(b_2)
print(id(b_1))
print(id(b_2))
- 建造者模式
包括一个限定方法抽象类,多个实际建造者类,一个指挥者类
以下情况适用:
1.当创建复杂对象的算法(Director)应该独立于该对象的组成部分以及它们的装配方式(Builder)时
2.当构造过程允许被构造的对象有不同的表示时(不同Builder)。
### 建造者模式
from abc import ABCMeta, abstractmethod
class Builder:
_metaClass_ = ABCMeta
@abstractmethod
def draw_body(self):
pass
class FatCreator(Builder):
def __init__(self):
...
def draw_body(self):
print(f'画胖子')
class ThinCreator(Builder):
def __init__(self):
pass
def draw_body(self):
print(f'画瘦子')
class Director:
def __init__(self, obj):
self.obj = obj
def draw(self):
self.obj.draw_body()
fat = FatCreator()
Director(fat).draw()
结构型模式
- 适配器模式
所谓适配器模式是指是一种接口适配技术,它可通过某个类来使用另一个接口与之不兼容的类,运用此模式,两个类的接口都无需改动。
适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况,比如在需要对早期代码复用一些功能等应用上很有实际价值。
### 适配器模式
class Target:
def request(self):
print("普通请求")
class Adaptee:
def special_request(self):
print("特殊请求")
class Adapter(Target):
def __init__(self):
self.adaptee = Adaptee()
def request(self):
self.adaptee.special_request()
target= Adapter()
target.request()
- 修饰器模式
Python种经典的模式,用来拓展类的功能
### 装饰器模式
import functools
def memoize(fn):
know = dict()
@functools.wraps(fn)
def memoizer(*args):
if args not in know:
know[args] = fn(*args)
return know[args]
return memoizer
@memoize
def nsum(n):
"""
返回前那个数的和
:param n:
:return:
"""
assert (n >= 0), 'n must be >= 0'
return 0 if n == 0 else n + nsum(n-1)
@memoize
def fibonacci(n):
"""
返回斐波那契数列的第n个数
:param n:
:return:
"""
assert n >= 0 and isinstance(n, int), 'n must be int and >= 0'
return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2)
from timeit import Timer
measure = [{'exec': 'fibonacci(100)', 'import': 'fibonacci', 'func': fibonacci},
{'exec': 'nsum(10)', 'import': 'nsum', 'func': nsum}]
for m in measure:
t = Timer(f'{m["exec"]}', f'from __main__ import {m["import"]}')
print('name: {} \ndoc: {} \nexecuting: {} \n time:{}'.format(m['func'].__name__, m['func'].__doc__, m['exec'], t.timeit()))
- 享元模式
运用共享技术有效地支持大量细粒度的对象。
内部状态:享元对象中不会随环境改变而改变的共享部分。比如围棋棋子的颜色。
外部状态:随环境改变而改变、不可以共享的状态就是外部状态。比如围棋棋子的位置。
应用场景:程序中使用了大量的对象,如果删除对象的外部状态,可以用相对较少的共享对象取代很多组对象,就可以考虑使用享元模式。
### 享元模式
class Tree(object):
obj_pool = {}
def __new__(cls, tree_type):
if tree_type not in cls.obj_pool:
obj = object.__new__(cls)
cls.obj_pool[tree_type] = obj
obj.tree_type = tree_type
return cls.obj_pool[tree_type]
def render(self, age):
print(f'{self.tree_type}: age: {age}')
# obj_list = []
# def __init__(self, tree_type):
# self.tree_type = tree_type
# self.get_obj()
# @classmethod
# def get_obj(cls):
# cls.obj_list.append(cls.__new__(cls))
from random import randint
for _ in range(10):
a = "apple"
t1 = Tree(a)
t1.render(randint(10, 50))
for _ in range(5):
t2 = Tree("cherry")
t2.render(randint(10, 50))
for _ in range(3):
t3 = Tree("peach")
t3.render(randint(10, 50))
print(len(Tree.obj_pool))
- 外观模式
外观模式又叫做门面模式。在面向对象程序设计中,解耦是一种推崇的理念。但事实上由于某些系统中过于复杂,从而增加了客户端与子系统之间的耦合度。例如:在家观看多媒体影院时,更希望按下一个按钮就能实现影碟机,电视,音响的协同工作,而不是说每个机器都要操作一遍。这种情况下可以采用外观模式,即引入一个类对子系统进行包装,让客户端与其进行交互。
外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
from enum import Enum
from abc import ABCMeta, abstractmethod
State = Enum('State', 'new running sleeping restart zombie')
class User:
pass
class Process:
pass
class File:
pass
class Server(metaclass=ABCMeta):
@abstractmethod
def __init__(self):
pass
def __str__(self):
return self.name
@abstractmethod
def boot(self):
pass
@abstractmethod
def kill(self, restart=True):
pass
class FileServer(Server):
def __init__(self):
'''初始化文件服务进程要求的操作'''
self.name = 'FileServer'
self.state = State.new
def boot(self):
print('booting the {}'.format(self))
'''启动文件服务进程要求的操作'''
self.state = State.running
def kill(self, restart=True):
print('Killing {}'.format(self))
'''终止文件服务进程要求的操作'''
self.state = State.restart if restart else State.zombie
def create_file(self, user, name, permissions):
'''检查访问权限的有效性、用户权限等'''
print("trying to create the file '{}' for user '{}' with permissions{}".format(name, user, permissions))
class ProcessServer(Server):
def __init__(self):
'''初始化进程服务进程要求的操作'''
self.name = 'ProcessServer'
self.state = State.new
def boot(self):
print('booting the {}'.format(self))
'''启动进程服务进程要求的操作'''
self.state = State.running
def kill(self, restart=True):
print('Killing {}'.format(self))
'''终止进程服务进程要求的操作'''
self.state = State.restart if restart else State.zombie
def create_process(self, user, name):
'''检查用户权限和生成PID等'''
print("trying to create the process '{}' for user '{}'".format(name, user))
class WindowServer:
pass
class NetworkServer:
pass
class OperatingSystem:
'''外观'''
def __init__(self):
self.fs = FileServer()
self.ps = ProcessServer()
def start(self):
[i.boot() for i in (self.fs, self.ps)]
def create_file(self, user, name, permissions):
return self.fs.create_file(user, name, permissions)
def create_process(self, user, name):
return self.ps.create_process(user, name)
def main():
os = OperatingSystem()
os.start()
os.create_file('foo', 'hello', '-rw-r-r')
os.create_process('bar', 'ls /tmp')