Python设计模式-读书笔记
2021-06-25 本文已影响0人
静赏月之美
设计模式
面向对象
对象
类
封装
多态
继承
抽象
组合
设计规则
不良设计主要表现在4个方面
- 不动性:以这种方式开发的应用程序非常难以重用。
- 刚性:以这种方式开发的应用程序,任何小的修改都会导致软件的太多部分必须进行相应的改动,所谓“牵一发而动全身”。
- 脆弱性:当前应用程序的任何更改都会导致现有系统变得非常容易崩溃。
- 粘滞性:由于架构层面的修改非常困难,因此修改必须由开发人员在代码或环境本身中进行。
创建型模式
单例模式
1、概念
- 确保类有且只有一个对象被创建
- 为对象提供一个访问点,以使程序可以全局访问该对象
- 控制共享资源的并行访问
- 所有的模块都是单例
2、基本实现
class Singleton(object):
def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
s_1 = Singleton()
s_2 = Singleton()
print("objected created", s_1)
print("objected created", s_2)
# objected created <__main__.Singleton object at 0x00000137A8ADFF10>
# objected created <__main__.Singleton object at 0x00000137A8ADFF10>
3、懒汉式实例化
# 懒汉式实例化
class Singleton:
__instance = None
def __init__(self) -> None:
if not Singleton.__instance:
print("__init__ method called..")
else:
print("Instance already created:", self.getInstance())
@classmethod
def getInstance(cls):
if not cls.__instance:
cls.__instance = Singleton()
return cls.__instance
# class initialized, but object not created
s = Singleton()
print("object created", Singleton.getInstance()) #Objcet gets created here
s1 = Singleton() # instance already created
'''
__init__ method called..
__init__ method called..
object created <__main__.Singleton object at 0x00000186165D2190>
Instance already created: <__main__.Singleton object at 0x00000186165D2190>
'''
4、Monostated单例模式
通常程序员需要的是让实例共享相同的状态,而不是同一性
本质是用类变量替换了__dict__
class Borg:
__shared_state = {}
def __init__(self) -> None:
self.x = 1
self.__dict__ = self.__shared_state
B1 = Borg()
B2 = Borg()
B1.x = 100
print("Borg B1:", B1)
print("Borg B2:", B2)
print("object state B1:", B1.__dict__)
print("object state B2:", B2.__dict__)
"""
Borg B1: <__main__.Borg object at 0x000002E1E7DE4220>
Borg B2: <__main__.Borg object at 0x000002E1E7DE4250>
object state B1: {'x': 100}
object state B2: {'x': 100}
"""
# 使用__new__方法来实现Borg
class Borg2:
_shared_state = {}
def __new__(cls, *args, **kwargs) -> Any:
obj = super(Borg2, cls).__new__(cls, *args, **kwargs)
obj.__dict__ = cls._shared_state
return obj
5、通过元类实现单例
# 元组
class MetaSingleton(type):
_instances = {}
def __call__(cls, *args, **kwds):
if cls not in cls._instances:
cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwds)
return cls._instances[cls]
class Logger(metaclass=MetaSingleton):
pass
logger1 = Logger()
logger2 = Logger()
print(logger1)
print(logger2)
"""
<__main__.Logger object at 0x000001A48982A5B0>
<__main__.Logger object at 0x000001A48982A5B0>
"""
6、 demo1
import sqlite3
class MetaSingleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Database(metaclass=MetaSingleton):
connection = None
def connect(self):
if self.connection is None:
self.connection = sqlite3.connect("db.sqlite3")
self.cursorobj = self.connection.cursor()
return self.cursorobj
db1 = Database().connect()
db2 = Database().connect()
print("db1:", db1)
print("db2:", db2)
demo2
class HealthCheck:
_instance = None
def __new__(cls, *args, **kwargs):
if not HealthCheck._instance:
HealthCheck._instance = super(HealthCheck, cls).__new__(cls, *args, **kwargs)
return HealthCheck._instance
def __init__(self) -> None:
self._servers = []
def addServer(self):
self._servers.append("Server 1")
self._servers.append("Server 2")
self._servers.append("Server 3")
self._servers.append("Server 4")
def changeServer(self):
self._servers.pop()
self._servers.append("Server 5")
hc1 = HealthCheck()
hc2 = HealthCheck()
hc1.addServer()
print("schedule health check for servers (1)...")
for i in range(4):
print("checking", hc1._servers[i])
hc2.changeServer()
print("schedule health check for servers (2)...")
for i in range(4):
print("checking", hc2._servers[i])
7、缺点
- 全局变量可能在某处已经被误改,但是开发人员仍然认为它们没有发生变化,而该变量还在应用程序的其他位置被使用。
- 可能会对同一对象创建多个引用。由于单例只创建一个对象,因此这种情况下会对同一个对象创建多个引用。
- 所有依赖于全局变量的类都会由于一个类的改变而紧密耦合为全局数据,从而可能在无意中影响另一个类。
工厂模式
1、“工厂”——一个负责创建其他类型对象的类
2、优点
- 松耦合,即对象的创建可以独立于类的实现
- 客户端无需了解创建对象的类,但是照样可以使用它来创建对象。它只需要知道需要传递的接口、方法和参数,就能够创建所需类型的对象了。这简化了客户端的实现
- 可以轻松地在工厂中添加其他类来创建其他类型的对象,而这无需更改客户端代码。最简单的情况下,客户端只需要传递另一个参数就可以了
- 工厂还可以重用现有对象。但是,如果客户端直接创建对象的话,总是创建一个新对象
3、3种变体
- 简单工厂模式
- 允许接口创建对象,但不会暴露对象的创建逻辑
- 工厂方法模式
- 允许接口创建对象,但使用哪个类来创建对象,则是交由子类决定的
from abc import ABC, ABCMeta, abstractmethod
class Section(metaclass=ABCMeta):
@abstractmethod
def describe(self):
psdd
class PersonScetion(Section):
def describe(self):
print("Personal Section")
class AlbumSection(Section):
def describe(self):
print("album Section")
class PatentSection(Section):
def describe(self):
print("Patent Section")
class PublicationSection(Section):
def describe(self):
print("Publication Section")
class Profile(metaclass=ABCMeta):
def __init__(self):
self.sections = []
self.createProfile()
@abstractmethod
def createProfile(self):
pass
def getSections(self):
return self.sections
def addSections(self, section):
self.sections.append(section)
class linkedin(Profile):
def createProfile(self):
self.addSections(PersonScetion())
self.addSections(PatentSection())
self.addSections(PublicationSection())
class facebook(Profile):
def createProfile(self):
self.sections.append(PersonScetion())
self.sections.append(AlbumSection())
if __name__ == "__main__":
profile_type= input("[LinkedIn or FaceBook]?")
profile = eval(profile_type.lower())()
print("creating profole..", type(profile).__name__)
print("Profile has sections -- ", profile.getSections())+-
- 抽象工厂模式
- 抽象工厂是一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象。
from abc import ABCMeta, abstractmethod
class PizzaFactory(metaclass=ABCMeta):
@abstractmethod
def cretaeVegPizza(self):
pass
@abstractmethod
def creatNonVegPizza(self):
pass
class IndiaPizzaFactory(PizzaFactory):
def cretaeVegPizza(self):
return DeluxVeggiePizza()
def creatNonVegPizza(self):
return ChickenPizza()
class USPizzaFactory(PizzaFactory):
def cretaeVegPizza(self):
return MexicanVegPizza()
def creatNonVegPizza(self):
return HamPizza()
class VegPizza(metaclass=ABCMeta):
@abstractmethod
def prepare(self, VegPizza):
pass
class NonVegPizza(metaclass=ABCMeta):
@abstractmethod
def serve(self, VegPizza):
pass
class DeluxVeggiePizza(VegPizza):
def prepare(self):
print("prepare", type(self).__name__)
class ChickenPizza(NonVegPizza):
def serve(self, VegPizza):
print(type(self).__name__, "is served with Chicken on ", type(VegPizza).__name__)
class MexicanVegPizza(VegPizza):
def prepare(self):
print("Prepare", type(self).__name__)
class HamPizza(NonVegPizza):
def serve(self, VegPizza):
print(type(self).__name__, "is served with Chicken on ", type(VegPizza).__name__)
class PizzaStore:
def __init__(self) -> None:
pass
def makePizzas(self):
for factory in [IndiaPizzaFactory(), USPizzaFactory()]:
self.factory = factory
self.NonVegPizza = self.factory.creatNonVegPizza()
self.vegPizza = self.factory.cretaeVegPizza()
self.vegPizza.prepare()
self.NonVegPizza.serve(self.vegPizza)
abcdd = USPizzaFactory()
pizza = PizzaStore()
pizza.makePizzas()
结构型设计模式
1、结构型设计模式
- 结构型模式描述如何将对象和类组合成更大的结构。
- 结构型模式是一种能够简化设计工作的模式,因为它能够找出更简单的方法来认识或表示实体之间的关系。在面向对象世界中,实体指的是对象或类。
- 类模式可以通过继承来描述抽象,从而提供更有用的程序接口,而对象模式则描述了如何将对象联系起来从而组合成更大的对象。结构型模式是类和对象模式的综合体。
门面设计模式
完成了下列事项:
- 它为子系统中的一组接口提供一个统一的接口,并定义一个高级接口来帮助客户端通过更加简单的方式使用子系统
- 门面所解决问题是,如何用单个接口对象来表示复杂的子系统。实际上,它并不是封装子系统,而是对底层子系统进行组合
- 它促进了实现与多个客户端的解耦
这个模式有3个主要的参与者:
- 门面:门面的主要责任是,将一组复杂导致系统封装起来,从而为外部世界提供一个舒适的外观。
- 系统:这代表一组不同的子系统,使整个系统混杂在一起,难以观察或使用
- 客户端:客户端与门面进行交互,这样就可以轻松地与子系统进行通信并完成工作了。不必担心系统的复杂性。
"""
门面设计模式
门面类 EventManager
"""
class EventManager:
def __init(self):
print("Event Manager:: Let me talk to the folfs \n")
def arrange(self):
self.hotelier = Hotelier()
self.hotelier.bookHotel()
self.florist = Florist()
self.florist.setFlowerRequirements()
self.caterer = Caterer()
self.caterer.setCuisine()
self.musician = Musician()
self.musician.setMusicType()
class Hotelier:
def __init__(self):
print("Arranging the Hotel for Marriage? --")
def __isAvailable(self):
print("Is the Hotel free for the event on given date?")
return True
def bookHotel(self):
if self.__isAvailable():
print("Registered the booking \n \n")
class Florist:
def __init__(self):
print("Flower Decorations for the Events? --")
def setFlowerRequirements(self):
print("Carnations, Roses and lilies would be used for Decorations \n\n")
class Caterer:
def __init__(self):
print("Food Arrangements for the Event --")
def setCuisine(self):
print("Chinese & Continental Cuisine to be served \n\n")
class Musician:
def __init__(self) -> None:
print("Musical Arrangements for the Marriage --")
def setMusicType(self):
print("Jazz and Classical will be played\n\n")
class You:
def __init__(self) -> None:
print("You:: Whos! Marriage Arrangements??!!!")
def askEventManager(self):
print("You:: Let's Contact the Event Manager \n\n")
em = EventManager()
em.arrange()
def __del__(self):
print("You:: Thanks to Event Manager, all prearations done!")
you = You()
you.askEventManager()
代理模式
在设计模式的上下文中,代理是充当实际对象接口的类。
代理就是封装实际服务对象的包装器或代理人。
代理可以为其包装的对象提供附加功能,而无需更改对象的代码。
代理模式的主要目的是为其他对象提供一个代理者或占位符,从而控制对实际对象的访问。
代理模式可以用于多种场景:
- 它能够以更简单的方式表示一个复杂的系统。例如,涉及多个复杂计算或过程的系统应该提供一个更简单的接口,让它充当客户端的代理。
- 它提高了现有的实际对象的安全性。在许多情况下,都不允许客户端直接访问实际对象。这是因为实际对象可能受到恶意活动的危害。这时候,代理就能起到抵御恶意活动的盾牌作用,从而保护了实际的对象。
- 它为不同服务器上的远程对象提供本地接口。一个明显的例子是客户端希望在远程系统上运行某些命令的分布式系统,但客户端可能没有直接的权限来实现这一点。
- 它为消耗大量内存的对象提供了一个轻量级的句柄。有时,你可能不想加载主要对象,除非它们真的有必要。
"""
代理
"""
from typing import AsyncGenerator
class Actor:
def __init__(self) -> None:
self.is_busy = False
def occuiped(self):
self.is_busy = True
print(type(self).__name__, "is occuiped with current movie")
def available(self):
self.is_busy = False
print(type(self).__name__, "is free for the movie")
def getStatus(self):
return self.is_busy
class Agent:
def __init__(self) -> None:
self.principal = None
self.actor = Actor()
def work(self):
if self.actor.getStatus():
self.actor.occuiped()
else:
self.actor.available()
if __name__ == "__main__":
r = Agent()
r.work()
代理模式有下述3个主要的参与者:
- 代理:它维护一个引用,允许代理(Proxy)通过这个引用来访问实际对象。它提供了一个与主题(Subject)相同的接口,以便代理可以替换真实的主题。代理还负责创建和删除真实主题(RealSubject)。
- 主题:它定义了RealSubject和Proxy的公共接口。以Proxy和RealSubject的形式实现主题(Subject),使用RealSubject的任何地方都可以使用代理(Proxy)
- 真实主题:它定义代理(Proxy)所代表的真实对象。
从数据结构的角度来看:
- 代理:它是一个控制对RealSubject类访问的类。它处理客户端的请求,负责创建或删除RealSubject。
- 主题/真实主题:主题是定义真实主题(RealSubject)和代理(Proxy)相类似的接口。RealSubject是Subject接口的实际实现。它提供了真正的功能,然后由客户端使用。
- 客户端:它访问要完成工作的Proxy类。Proxy类在内部控制对RealSubject的访问,并引导客户端(Client)所请求的工作。
根据代理的使用方式,我们可以将它们分为虚拟代理、远程代理、保护代理和智能代理。
虚拟代理
如果一个对象实例化后会占用大量内存的话,可以先利用占位符来表示,这就是所谓的虚拟代理。
远程代理
它给位于远程服务器或不同地址空间上的实际对象提供了一个本地表示
保护代理
这种代理能够控制RealSubject的敏感对象的访问。
智能代理
智能代理在访问对象时插入其他操作。
from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def do_pay(self):
pass
class Bank(Payment):
def __init__(self) -> None:
self.card = None
self.account = None
def __getAccount(self):
self.account = self.card
return self.account
def __hasFunds(self):
print("Bank:: Checking if Account", self.__getAccount(), "has enough funds")
return True
def setCard(self, card):
self.card = card
def do_pay(self):
if self.__hasFunds():
print("Bank:: Paying the merchant")
return True
else:
print("Bank:: Sorry, not enough funds!")
return False
class DebitCard(Payment):
def __init__(self) -> None:
self.bank = Bank()
def do_pay(self):
card = input("Proxy:: Punch in Card Number")
self.bank.setCard(card)
return self.bank.do_pay
class You:
def __init__(self) -> None:
print("You:: Lets buy the Denim shirt")
self.debitCard = DebitCard()
self.isPurchased = None
def make_payment(self):
self.isPurchased = self.debitCard.do_pay()
def __del__(self):
if self.isPurchased:
print("You:: Wow! Denim shirt is Mine")
else:
print("You:: I should earn more:")
if __name__ == "__main__":
you = You()
you.make_payment()
代理模式的优点:
- 代理可以通过缓存笨重的对象或频繁访问的对象来提高应用程序的性能
- 代理还提供对于真实主题的访问授权。因此,只有提供合适权限的情况下,这个模式才会接受委派。
- 远程代理还便于与可用作网络连接和数据库连接的远程服务器进行交互,并可用于监视系统。
行为型模式
观察者模式
观察者模式的主要目标:
- 它定义了对象之间的一对多的依赖关系,从而使得一个对象中的任何更改都将自动通知给其他依赖对象;
- 它封装了主题的核心组件。
观察者模式工作场景:
- 在分布式系统中实现事件服务
- 用作新闻机构的框架
- 股票市场
from abc import ABCMeta, abstractmethod
from typing import Any
class NewsPublisher:
def __init__(self):
self.__subscribers = []
self.__latest_news = None
def attach(self, subscriber):
self.__subscribers.append(subscriber)
def detach(self):
return self.__subscribers.pop()
def subscribers(self):
return [type(sub).__name__ for sub in self.__subscribers]
def notify_subscribers(self):
for sub in self.__subscribers:
sub.update()
def add_news(self, news):
self.__latest_news = news
def getNews(self):
return 'Got News:', self.__latest_news
class Subscriber(metaclass=ABCMeta):
@abstractmethod
def update(self):
pass
class SMSSubscriber:
def __init__(self, publisher) -> None:
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
class EmailSubscriber:
def __init__(self, publisher) -> None:
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
class AnyOtherSubscriber:
def __init__(self, publisher):
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
if __name__ == '__main__':
news_publisher = NewsPublisher()
for subscriber in [SMSSubscriber, EmailSubscriber, AnyOtherSubscriber]:
subscriber(news_publisher)
print(news_publisher.subscribers)
news_publisher.add_news("hello world")
news_publisher.notify_subscribers()
print("\n Detached:", type(news_publisher.detach()).__name__)
print("\nSubscribers:", news_publisher.subscribers())
news_publisher.add_news("second news")
news_publisher.notify_subscribers()
命令设计模式
命令模式优点:
- 将调用操作的类与知道如何执行该操作的对象解耦
- 提供队列系统后,可以创建一系列命令
- 添加新命令更加容易,并且无需更改现有代码
- 使用命令模式来定义回滚系统
from abc import ABC, ABCMeta, abstractmethod
class Command(metaclass=ABCMeta):
def __init__(self, recv):
self.recv = recv
@abstractmethod
def execute(self):
pass
class ConcreteCommand(Command):
def __init__(self, recv):
self.recv = recv
def execute(self):
self.recv.action()
class Receiver:
def action(self):
print("Receiver Action")
class Invoker:
def command(self, cmd):
self.cmd = cmd
def execute(self):
self.cmd.execute()
if __name__ = '__main__':
recv = Receiver()
cmd = ConcreteCommand(recv)
invoker = Invoker()
invoker.command(cmd)
invoker.execute()
from abc import ABCMeta, abstractmethod
class Order(metaclass=ABCMeta):
@abstractmethod
def execute(self):
pass
class BuyStockOrder(Order):
def __init__(self, stock):
self.stock = stock
def execute(self):
self.stock.buy()
class SellStockOrder(Order):
def __init__(self, stock):
self.stock = stock
def execute(self):
self.stock.sell()
class StockTrade:
def buy(self):
print("you will buy stocks")
def sell(self):
print("you will sell stocks")
class Agent:
def __init__(self):
self.__orderQueue = []
def placeOrder(self, order):
self.__orderQueue.append(order)
order.execute()
if __name__ == '__main__':
# Client
stock = StockTrade()
buyStock = BuyStockOrder(stock)
sellStock = SellStockOrder(stock)
# Invoker
agent = Agent()
agent.placeOrder(buyStock)
agent.placeOrder(sellStock)
模板设计模式
模板方法模式象适用场景:
- 当多个算法或类实现类似或相同逻辑的时候;
- 在子类中实现算法有助于减少重复代码的时候
- 可以让子类利用覆盖实现行为来定义多个算法的时候
模板方法模式的优点:
- 没有代码重复
- 由于模板方法模式使用继承而不是合成,因此能够对代码进行重用。所以,只有为数不多的几个方法需要重写
- 灵活性允许子类决定如何实现算法中的步骤。
from abc import ABCMeta, abstractmethod
class Trip(metaclass=ABCMeta):
@abstractmethod
def setTransport(self):
pass
@abstractmethod
def day1(self):
pass
@abstractmethod
def day2(self):
pass
@abstractmethod
def day3(self):
pass
@abstractmethod
def returnHome(self):
pass
def itinerary(self):
self.setTransport()
self.day1()
self.day2()
self.day3()
self.returnHome()
class VeniceTrip(Trip):
def setTransport(self):
print("take a boat and find your way in the Grand Canal")
def day1(self):
print("day1,Venice vist...")
def day2(self):
print("day2,Venice vist...")
def day3(self):
print("day3,Venice vist...")
def returnHome(self):
print("Venice go home")
class MaldiversTrip(Trip):
def setTransport(self):
print("on foot...")
def day1(self):
print("day1,Maldivers vist...")
def day2(self):
print("day2,Maldivers vist...")
def day3(self):
print("day3,Maldivers vist...")
def returnHome(self):
print("Maldivers go home")
class TravelAgency:
def __init__(self) -> None:
self.trip = None
def arrangeTrip(self):
choice = input("Venice or Maldivers?")
if choice == "Venice":
self.trip = VeniceTrip()
self.trip.itinerary()
if choice == "Maldivers":
self.trip = MaldiversTrip()
self.trip.itinerary()
if __name__ == "__main__":
customer = TravelAgency()
customer.arrangeTrip()
状态设计模式
状态模式也可以看作是在运行时改变对象行为的一种方式。
状态模式的优点:
- 在状态设计模式中,对象的行为是其状态的函数结果,并且行为在运行时根据状态而改变
- 使用状态模式,实现多态行为的好处是显而易见的,并且更易于添加状态来支持额外的行为。
- 状态设计模式还提高了聚合性,因为特定于状态的行为被聚合到ConcreteState类中,并且放置在代码中的同一个地方
- 使用状态设计模式,通过只添加一个ConcreteState类来添加行为是非常容易的。因此,状态模式不仅改善了扩展应用程序行为时的灵活性,而且全面提高了代码的可维护性。
from abc import abstractmethod, ABCMeta
class State(metaclass=ABCMeta):
@abstractmethod
def Handle(self):
pass
class ConcreteStateB(State):
def Handle(self):
print("Concrete State B")
class ConcreteStateA(State):
def Handle(self):
print("Concrete State A")
class Context(State):
def __init__(self):
self.state = None
def getState(self):
return self.state
def setState(self, state):
self.state= state
def Handle(self):
self.state.Handle()
if __name__ == '__main__':
context = Context()
stateA = ConcreteStateA()
stateB = ConcreteStateB()
context.setState(stateA)
context.Handle()
复合模式
复合模式将两个或更多模式组合成解决常见或普遍性问题的解决方案。
MVC模式(模型-试图-控制器模式)
MVC模式的工作机制:
- 模型提供数据和业务逻辑
- 视图负责数据的展示
- 控制器是两者的粘合剂
MVC模式应用场景:
- 当需要更改展示方式而不更改业务逻辑时
- 多个控制器可用于使用多个视图来更改用户界面上的展示
- 当模型改变时,视图无需改动
MVC模式的优点
- 有助于提高可维护性,强制松耦合,并降低复杂性
- MVC允许对前端进行独立更改,而对后端逻辑无需任何修改或只需进行很少的更改,因此开发工作仍可以独立运行
- 可以更改模型或业务逻辑,而无需对视图进行任何更改
- 可以更改控制器,而不会对视图或模型造成任何影响
class Model:
services = {
'emial': {"number": 1000, 'price': 2},
'sms': {'number': 1000, 'price': 10},
'voice': {'number': 1000, 'price': 15}
}
class View:
def list_services(self, services):
for svc in services:
print(svc, " ")
def list_pricing(self, services):
for svc in services:
print('For', Model.services[svc]['number'], svc, 'message you pay $', Model.services[svc]['price'])
class Controller:
def __init__(self) -> None:
self.model = Model()
self.view = View()
def get_services(self):
services = self.model.services.keys()
return self.view.list_services(services)
def get_pricing(self):
services = self.model.services.keys()
return self.view.list_pricing(services)
if __name__ == '__main__':
controller = Controller()
print("Services Provided:")
controller.get_services()
print("Pricing for Services:")
controller.get_pricing()