python设计模式之原型模式

1. 原型模式

原型模式通过复制现有的对象来创建新对象,而不是通过实例化类来创建对象,对此你一定感到困惑,什么样的情况下需要这样做呢,命名实例化类就能创建对象,为什么非要复制?

理解设计模式的一个难点就在于我们总是希望能有一个合理的应用场景来帮助理解某一种设计模式的必要性与合理性,然而几乎大多数的教程都不涉及这些,这导致在学习过程中对设计模式总是存在各种质疑和不解。

原型模式适用的场景有这样的特点:

  1. 需要大量的创建对象
  2. 通过实例化类创建对象比较耗时费力

举一个例子,在战争射击类游戏中,你的面前会出现大量地方士兵,在程序里,每一个士兵就是一个对象,为了理解方便,我简化士兵对象,一个士兵对象有血量,攻击力,防御力三个属性,这些属性肯定不会在代码里写死的,而是存储配置文件中,也可能是存储在数据库中,这样更新游戏的时候,只需要更新配置文件或者数据库就可以随时调整一个士兵的属性。

创建一个士兵对象后,要加载这些属性,不论是从配置文件还是从数据库加载,这都是一个耗时的操作,当有大量士兵对象需要初始化时,如果都采用实例化类的方法,那么每个对象就都需要加载一次属性,这样做很耗时,如果能根据已有的士兵对象复制出一个新的对象,那么就不需要执行加载属性的方法了,这样就可以节省时间。

2. python实现

原型模式通常包括以下三个角色:

  1. 原型(Prototype):定义了一个克隆自身的接口,用于复制现有对象。
  2. 具体原型(Concrete Prototype):实现了原型接口,负责复制自身。
  3. 客户端(Client):使用原型接口来复制现有对象,并创建新对象。

下面是原型模式的简单示例

import copy
from abc import ABC, abstractmethod


class Prototype(ABC):
    @abstractmethod
    def clone(self) -> None:
        pass


class SoldierPrototype(Prototype):
    def __init__(self):
        self.blood = None               # 血量
        self.attack_power = None        # 攻击力
        self.defense_power = None       # 防御力

    def load_config(self):
        """
        这里假设根据配置文件加载对象属性是一个耗时的操作
        :return:
        """
        self.blood = 100
        self.attack_power = 90
        self.defense_power = 80

    def clone(self):
        return copy.deepcopy(self)


soldier_prototype = SoldierPrototype()
soldier_prototype.load_config()

soldier_lst = [soldier_prototype.clone() for i in range(100)]
print(soldier_lst[0].blood)

程序先创建一个SoldierPrototype示例对象,接下来调用load_config方法加载对象的属性,这里咱们必须加载load_config方法是一个高成本的操作,有了这个原型对象后,就可以根据它来创建更多的士兵对象,每个士兵对象都是一模一样的,没必要每个士兵对象都去调用load_config方法来加载属性。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案