前言
这篇主要总结下 设计模式: 工厂模式、策略模式、生产者-消费者模式, 用python举例说明
一、策略模式
1.1 理论理解
顾名思义,根据情况来选择不一样的《策略》。
这种设计模式主要适用于: 希望能够根据特定条件选择方法的情况。 想根据具体场景理解可以看:https://cloud.tencent.com/developer/article/1774687 , 简而言之,根据不同的算法选择,来调用对应的方法,为了更加可维护且运行时动态切换方法等,采用这种模式
1.2 举例
如何根据不同的排序算法来对列表进行排序。
首先,定义一个抽象策略类 SortStrategy,其中包含一个抽象方法 sort,用于定义具体的排序算法。
from abc import ABC, abstractmethod
class SortStrategy(ABC):
@abstractmethod
def sort(self, data):
pass
通过继承SortStrategy, 创建具体的排序策略类 BubbleSort 和 QuickSort,它们分别实现了抽象方法sort。
class BubbleSort(SortStrategy):
def sort(self, data):
# 使用冒泡排序算法对数据进行排序
pass
class QuickSort(SortStrategy):
def sort(self, data):
# 使用快速排序算法对数据进行排序
pass
定义一个上下文类 SorterContext,它负责调用具体的排序策略
class SorterContext:
def __init__(self, strategy):
self.strategy = strategy
def sort_data(self, data):
self.strategy.sort(data)
最终应用
if __name__ == '__main__':
data = [15, 2, 8, 1, 9]
bubble_sort_strategy = BubbleSort()
sorter1 = SorterContext(bubble_sort_strategy)
sorter1.sort_data(data)
print(f"Bubble Sort: {data}")
quick_sort_strategy = QuickSort()
sorter2 = SorterContext(quick_sort_strategy)
sorter2.sort_data(data)
print(f"Quick Sort: {data}")
二、工厂模式
主要分为三类
简单工厂模式
工厂方法模式
抽象工厂模式
2.1 简单工厂模式
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "wang!"
class Cat(Animal):
def speak(self):
return "miao!"
class AnimalFactory:
@staticmethod
def create_animal(animal_type):
if animal_type == 'Dog':
return Dog('Dog')
elif animal_type == 'Cat':
return Cat('Cat')
else:
raise ValueError('Invalid animal type')
animal = AnimalFactory.create_animal('Dog')
print(animal.speak())
AnimalFactory 是一个简单工厂类,通过静态方法 create_animal 来创建不同类型的动物。
通过传入不同的 animal_type 参数,可以创建不同的动物对象。
所以简单工厂模式主要是实现 统一接口,通过type去决定实例化哪个类。
优缺点
优点:
将对象的创建逻辑封装在工厂类中,对类的使用只需要与工厂类进行交互,统一了对外的接口。
简单高效
缺点:
违反了开闭原则(对扩展开放,对修改关闭),当扩展添加新的产品类型时,需要修改工厂类的代码,不符合这个原则,比如想新增一个动物,得改变create_animal中对应的逻辑
工厂类集中了创建产品的逻辑,当产品较多时,工厂类会变得庞大,代码可读性和可维护性下降。
总结:简单工厂模式适用于需要创建的产品类型较少且不经常变化的情况下,比如业务里已经明确的类型,它能够封装对象的创建过程,提供了一种简单的创建对象的方式。但是当产品类型较多或需要频繁添加新产品时,简单工厂模式的缺点就会显现出来,不利于扩展和维护。在这种情况下,可以考虑使用工厂方法模式或抽象工厂模式来解决这些问题。
2.2 工厂方法模式
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "wang!"
class Cat(Animal):
def speak(self):
return "miao!"
# 抽象工厂类:每种动物都有自己对于的creator工厂
class AnimalCreator(ABC):
@abstractmethod
def create_animal(self):
pass
class DogCreator(AnimalCreator):
def create_animal(self):
return Dog()
class CatCreator(AnimalCreator):
def create_animal(self):
return Cat()
dog_creator = DogCreator()
dog = dog_creator.create_animal()
print(dog.speak())
cat_creator = CatCreator()
cat = cat_creator.create_animal()
print(cat.speak())
在这个例子中,AnimalCreator 是一个抽象创建者类,其中定义了一个抽象的工厂方法 create_animal。具体的创建者类 DogCreator 和 CatCreator 分别实现了工厂方法,用于创建不同类型的动物对象。
优缺点
优点:
符合开闭原则,当需要添加新的类型时,只需要添加新的具体创建者类,不需要修改抽象创建者类或客户端代码。
每个具体创建者类只负责创建一种产品类型的对象,使得代码更加清晰和易于扩展。
缺点:
当产品类型较多时,创建者类的数量会增加,增加了代码的复杂性。
调用方会稍微复杂一些,因为还要了解下创建者类
总结:工厂方法模式适用于子类很多且需要频繁添加新产品的情况以及对于添加的新产品是未知的情况下,它将对象的创建延迟到具体创建者类中,每个具体创建者类负责创建一种产品类型的对象,符合开闭原则,方便了产品的扩展。但是它也增加了类的数量和客户端代码的复杂性,需要权衡使用。
2.2 工厂方法模式
抽象工厂模式是工厂方法模式的升级版本,在有多个分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
from abc import ABC, abstractmethod
class Button(ABC):
@abstractmethod
def render(self):
pass
class MacOSButton(Button):
def render(self):
return 'Render MacOS Button'
class WindowsButton(Button):
def render(self):
return 'Render Windows Button'
class Checkbox(ABC):
@abstractmethod
def render(self):
pass
class MacOSCheckbox(Checkbox):
def render(self):
return 'Render MacOS Checkbox'
class WindowsCheckbox(Checkbox):
def render(self):
return 'Render Windows Checkbox'
class GUIFactory(ABC):
@abstractmethod
def create_button(self):
pass
@abstractmethod
def create_checkbox(self):
pass
class MacOSFactory(GUIFactory):
def create_button(self):
return MacOSButton()
def create_checkbox(self):
return MacOSCheckbox()
class WindowsFactory(GUIFactory):
def create_button(self):
return WindowsButton()
def create_checkbox(self):
return WindowsCheckbox()
macos_factory = MacOSFactory()
button = macos_factory.create_button()
checkbox = macos_factory.create_checkbox()
print(button.render())
print(checkbox.render())
windows_factory = WindowsFactory()
button = windows_factory.create_button()
checkbox = windows_factory.create_checkbox()
print(button.render())
print(checkbox.render())
GUIFactory 是一个抽象工厂类,其中定义了创建按钮(Button)和复选框(Checkbox)的抽象方法 create_button 和 create_checkbox。具体工厂类 MacOSFactory 和 WindowsFactory 分别实现了这些抽象方法,用于创建不同平台下的按钮和复选框对象。
优缺点
优点
将一组相关的产品对象的创建逻辑封装在一个工厂类中,使得调用方与具体产品的创建逻辑解耦,调用方只需要与抽象工厂类进行交互
缺点
当需要添加新的产品类型时,需要修改抽象工厂类和所有具体工厂类的代码,不符合开闭原则。
随着产品系列的增加,会比较大的增加代码的复杂性。
总结:相比工厂方法模式只有1种create,当你要新增一类产品的时候,得重新创建工厂接口类。 而抽象工厂中,直接工厂接口类上新增方法,后面的子类同一实现即可,但有个前提条件是这些子类是一个group,有一定的相关和组别性质。
三、生产者-消费者模式
import threading
import time
import random
from queue import Queue
# 创建一个队列作为共享的缓冲区
buffer = Queue(maxsize=10)
# 定义生产者类
class Producer(threading.Thread):
def run(self):
while True:
# 缓冲区已满,等待
if buffer.full():
print("Buffer is full, waiting for consumer to consume...")
time.sleep(random.randint(1, 3))
else:
# 生产一个随机数并添加到缓冲区
num = random.randint(1, 100)
buffer.put(num)
print(f"Produced: {num}")
time.sleep(1)
# 定义消费者类
class Consumer(threading.Thread):
def run(self):
while True:
# 缓冲区为空,等待
if buffer.empty():
print("Buffer is empty, waiting for producer to produce...")
time.sleep(random.randint(1, 3))
else:
# 从缓冲区取出一个随机数并消费
num = buffer.get()
print(f"Consumed: {num}")
time.sleep(1)
# 创建生产者和消费者线程并启动
producer = Producer()
consumer = Consumer()
producer.start()
consumer.start()
使用Queue模块来创建一个大小为10的队列作为共享的缓冲区。生产者不断产生随机数并将其放入队列中,消费者不断从队列中取出随机数进行消费。使用Queue模块可以避免手动处理锁等线程同步机制,因为Queue提供了内置的线程安全机制。
四、集成三种模式的demo
首先,定义一个抽象产品类 Product,其中包含一个抽象方法 calculate_discount,用于计算折扣后的价格。
class Product(ABC):
def __init__(self):
self.price = None
@abstractmethod
def calculate_discount(self):
pass
def set_price(self, price):
self.price = price
然后,创建具体的商品类 Book、Electronic,分别实现抽象方法
class Book(Product):
def calculate_discount(self):
# 具体的书籍折扣计算逻辑
return 0.9 # 10% off
class Electronic(Product):
def calculate_discount(self):
# 具体的电子产品折扣计算逻辑
return 0.8 # 20% off
接下来,定义一个抽象工厂类 ProductFactory,其中包含一个抽象方法 create_product,用于创建具体的产品对象。
class ProductFactory(ABC):
@abstractmethod
def create_product(self):
pass
创建具体的工厂类 BookFactory、ElectronicFactory
class BookFactory(ProductFactory):
def create_product(self):
return Book()
class ElectronicFactory(ProductFactory):
def create_product(self):
return Electronic()
定义一个抽象折扣策略类 DiscountStrategy,其中包含一个抽象方法 apply_discount 用于应用折扣策略
class DiscountStrategy(ABC):
@abstractmethod
def apply_discount(self, product):
pass
创建具体的折扣策略类 PercentOffStrategy 和 FixedAmountOffStrategy
class PercentOffStrategy(DiscountStrategy):
def __init__(self, percent):
self.percent = percent
def apply_discount(self, product):
discount = product.calculate_discount()
discounted_price = product.price * (1 - discount * self.percent)
return discounted_price
class FixedAmountOffStrategy(DiscountStrategy):
def __init__(self, amount):
self.amount = amount
def apply_discount(self, product):
discount = product.calculate_discount()
discounted_price = product.price - (self.amount * discount)
return discounted_price
定义一个生产者类 Producer,它生成不同类型的商品对象,并将其放入队列中
import time
from threading import Thread
from queue import Queue
class Producer(Thread):
def __init__(self, queue, factory, price_max, price_min):
super().__init__()
self.queue = queue
self.factory = factory
self.price_max = price_max
self.price_min = price_min
def run(self):
while True:
# 生成商品,并放入队列中
product = self.factory.create_product()
price = random.randint(self.price_min, self.price_max)
product.set_price(price)
self.queue.put(product)
time.sleep(5) # 模拟生成商品的耗时操作
定义一个消费者类 Consumer,它从队列中获取商品对象,并根据折扣策略进行折扣操作
class Consumer(Thread):
def __init__(self, queue, discount_strategy):
super().__init__()
self.queue = queue
self.discount_strategy = discount_strategy
def run(self):
while True:
# 从队列中获取商品,并应用折扣策略
product = self.queue.get()
discounted_price = self.discount_strategy.apply_discount(product)
# 处理折扣后的价格逻辑
print(f"Discounted price of {type(product).__name__}: {discounted_price}")
main函数
if __name__ == '__main__':
queue = Queue()
book_factory = BookFactory()
producer1 = Producer(queue, book_factory, 50, 10)
producer1.start()
electronic_factory = ElectronicFactory()
producer2 = Producer(queue, electronic_factory, 200, 100)
producer2.start()
percent_off_strategy = PercentOffStrategy(0.2)
consumer1 = Consumer(queue, percent_off_strategy)
consumer1.start()
fixed_amount_off_strategy = FixedAmountOffStrategy(50)
consumer2 = Consumer(queue, fixed_amount_off_strategy)
consumer2.start()
完整代码
import random
import time
from threading import Thread
from queue import Queue
from abc import ABC, abstractmethod
class Product(ABC):
def __init__(self):
self.price = None
@abstractmethod
def calculate_discount(self):
pass
def set_price(self, price):
self.price = price
class Book(Product):
def calculate_discount(self):
# 具体的书籍折扣计算逻辑
return 0.9 # 10% off
class Electronic(Product):
def calculate_discount(self):
# 具体的电子产品折扣计算逻辑
return 0.8 # 20% off
class ProductFactory(ABC):
@abstractmethod
def create_product(self):
pass
class BookFactory(ProductFactory):
def create_product(self):
return Book()
class ElectronicFactory(ProductFactory):
def create_product(self):
return Electronic()
class DiscountStrategy(ABC):
@abstractmethod
def apply_discount(self, product):
pass
class PercentOffStrategy(DiscountStrategy):
def __init__(self, percent):
self.percent = percent
def apply_discount(self, product):
discount = product.calculate_discount()
discounted_price = product.price * (1 - discount * self.percent)
return discounted_price
class FixedAmountOffStrategy(DiscountStrategy):
def __init__(self, amount):
self.amount = amount
def apply_discount(self, product):
discount = product.calculate_discount()
discounted_price = product.price - (self.amount * discount)
return discounted_price
class Producer(Thread):
def __init__(self, queue, factory, price_max, price_min):
super().__init__()
self.queue = queue
self.factory = factory
self.price_max = price_max
self.price_min = price_min
def run(self):
while True:
# 生成商品,并放入队列中
product = self.factory.create_product()
price = random.randint(self.price_min, self.price_max)
product.set_price(price)
self.queue.put(product)
time.sleep(5) # 模拟生成商品的耗时操作
class Consumer(Thread):
def __init__(self, queue, discount_strategy):
super().__init__()
self.queue = queue
self.discount_strategy = discount_strategy
def run(self):
while True:
# 从队列中获取商品,并应用折扣策略
product = self.queue.get()
discounted_price = self.discount_strategy.apply_discount(product)
# 处理折扣后的价格逻辑
print(f"Discounted price of {type(product).__name__}: {discounted_price}")
if __name__ == '__main__':
queue = Queue()
book_factory = BookFactory()
producer1 = Producer(queue, book_factory, 50, 10)
producer1.start()
electronic_factory = ElectronicFactory()
producer2 = Producer(queue, electronic_factory, 200, 100)
producer2.start()
percent_off_strategy = PercentOffStrategy(0.2)
consumer1 = Consumer(queue, percent_off_strategy)
consumer1.start()
fixed_amount_off_strategy = FixedAmountOffStrategy(50)
consumer2 = Consumer(queue, fixed_amount_off_strategy)
consumer2.start()
参考
https://bbs.huaweicloud.com/blogs/281878
https://www.cnblogs.com/Zzbj/p/15778464.html
https://zhuanlan.zhihu.com/p/591928172
https://cloud.tencent.com/developer/article/1774687
推荐阅读:
我的2022届互联网校招分享
我的2021总结
浅谈算法岗和开发岗的区别
互联网校招研发薪资汇总
公众号:AI蜗牛车
保持谦逊、保持自律、保持进步
发送【蜗牛】获取一份《手把手AI项目》(AI蜗牛车著)
发送【1222】获取一份不错的leetcode刷题笔记
发送【AI四大名著】获取四本经典AI电子书