设计模式学习手册(四)(原型模式)

写在前面

  • 书接上文设计模式学习手册(三)(建造者模式)
  • 原型模式简单来说就是复制一个已存在的原型实例,并对其进行必要的修改,来创建新的对象。原型模式通常会有一个clone()方法用于复制对象。
  • 优点:
    • 直接复制现有对象,避免了重复的初始化过程,减少开销。
    • 可以动态地改变克隆对象的属性,适应不同的需求。
    • 无需关心对象的构造细节,通过复制现有实例即可创建新对象。
  • 缺点:
    • 会涉及到编程中的一个经典问题:深浅拷贝
    • Clone方法位于类的内部,改造的时候需要修改代码,违背了开闭原则;
    • 并不是所有对象都适合使用原型模式,尤其是那些具有复杂依赖关系或资源限制的对象

原型模式的简单尝试

  • 先尝试有一种传统的写法,需要不断的创建新的实例,当构造函数涉及到的属性很多后,这种方式就显得效率低下了
python 复制代码
class person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def todict(self):
        return {"name": self.name, "age": self.age}


if __name__ == '__main__':
    a = person("John", 25)
    b = person("John", 25)
    c = person("John", 25)

    print(a.todict())
    print(b.todict())
    print(c.todict())
  • 还有一种写法,直接把a引用所指向的地址赋值给b和c,但要注意,当你修改a的时候,b和c也会同时变化
python 复制代码
if __name__ == '__main__':
    a = person("John", 25)
    b = a
    c = a

    a.name = "Jane"

    print(a.todict())
    print(b.todict())
    print(c.todict())
  • 使用原型模式
python 复制代码
import copy


# 原型接口
class Prototype:
    def clone(self):
        pass


# 具体原型类
class ConcretePrototype(Prototype):
    def __init__(self, name, interests):
        self.name = name
        self.interests = interests  

    def get_name(self):
        return self.name

    def get_interests(self):
        return self.interests

    def clone(self):
        # 使用浅拷贝
        return copy.copy(self)


# 客户端代码
if __name__ == "__main__":
    prototype1 = ConcretePrototype("jack", ['classical music', 'rock music'])
    prototype2 = prototype1.clone()

    print(f"Prototype 1: {prototype1.get_name()}, Items: {prototype1.get_interests()}")
    print(f"Prototype 2: {prototype2.get_name()}, Items: {prototype2.get_interests()}")
  • 原型模式一般有以下2个组成
    • 原型接口 :定义一个接口,要求实现该接口的类必须提供一个克隆自身的功能。通常,clone()方法用于复制对象。
    • 具体原型类:实现原型接口的类,负责实现具体的克隆逻辑。

原型模式之深拷贝

浅拷贝

在上面的示例代码中,尝试下修改属性

python 复制代码
if __name__ == "__main__":
    prototype1 = ConcretePrototype("jack", ['classical music', 'rock music'])
    prototype2 = prototype1.clone()

    # 修改 prototype2 的 interests 属性
    prototype2.get_interests().append('jazz music')
    prototype1.name = "jane"

    print(f"Prototype 1: {prototype1.get_name()}, Items: {prototype1.get_interests()}")
    print(f"Prototype 2: {prototype2.get_name()}, Items: {prototype2.get_interests()}")
    
# Output:
# Prototype 1: jane, Items: ['classical music', 'rock music', 'jazz music']
# Prototype 2: jack, Items: ['classical music', 'rock music', 'jazz music']

不难发现修改name属性,不会相互影响,但是修改interests属性,prototype1prototype2都受到了影响。主要原因是:浅拷贝中的元素,只拷贝了表面的一层,因此,如果原对象中包含了引用对象,改变其也会影响拷贝后的对象

深拷贝

  • 只要修改clone函数即可
  • 深度拷贝则会递归地拷贝原对象中的每一个子对象,因此拷贝后的对象和原对象互不相关
python 复制代码
import copy


# 原型接口
class Prototype:
    def clone(self):
        pass


# 具体原型类
class ConcretePrototype(Prototype):
    def __init__(self, name, interests):
        self.name = name
        self.interests = interests  

    def get_name(self):
        return self.name

    def get_interests(self):
        return self.interests

    def clone(self):
        # 使用浅拷贝
        return copy.deepcopy(self)


# 客户端代码
if __name__ == "__main__":
    prototype1 = ConcretePrototype("jack", ['classical music', 'rock music'])
    prototype2 = prototype1.clone()

    # 修改 prototype2 的 interests 属性
    prototype2.get_interests().append('jazz music')
    prototype1.name = "jane"

    print(f"Prototype 1: {prototype1.get_name()}, Items: {prototype1.get_interests()}")
    print(f"Prototype 2: {prototype2.get_name()}, Items: {prototype2.get_interests()}")

# Output:
# Prototype 1: jane, Items: ['classical music', 'rock music']
# Prototype 2: jack, Items: ['classical music', 'rock music', 'jazz music']

原型模式+工厂模式

  • 原型模式实际项目中,使用的场景并不多,但原型模式常常和其他的设计模式混搭着使用,这里就简单写了个demo
python 复制代码
import copy


# 原型接口
class Prototype:
    def clone(self):
        pass


# 具体原型类
class ConcretePrototype(Prototype):
    def __init__(self, name, interests):
        self.name = name
        self.interests = interests

    def get_name(self):
        return self.name

    def get_interests(self):
        return self.interests

    def clone(self):
        # 返回一个克隆对象
        return copy.deepcopy(self)


# 工厂类,用于生产对象
class PrototypeFactory:
    def __init__(self):
        # 初始化时可以设置多个原型对象
        self.prototypes = {}

    def register_prototype(self, name, prototype):
        """ 注册原型对象 """
        self.prototypes[name] = prototype

    def create_prototype(self, name):
        """ 根据名字克隆原型对象 """
        prototype = self.prototypes.get(name)
        if prototype:
            return prototype.clone()
        else:
            print(f"Prototype {name} not found!")
            return None


# 客户端代码
if __name__ == "__main__":
    # 创建原型对象
    prototype1 = ConcretePrototype("jack", ['classical music', 'rock music'])
    prototype2 = ConcretePrototype("alice", ['jazz music', 'pop music'])

    # 创建工厂对象并注册原型
    factory = PrototypeFactory()
    factory.register_prototype("jackPrototype", prototype1)
    factory.register_prototype("alicePrototype", prototype2)

    # 通过工厂创建新的对象
    cloned_object1 = factory.create_prototype("jackPrototype")
    cloned_object2 = factory.create_prototype("alicePrototype")

    # 修改克隆对象的属性
    cloned_object1.get_interests().append("hip hop")
    cloned_object2.get_name()  # "alice"

    # 输出克隆对象的属性
    print(f"Cloned Object 1: {cloned_object1.get_name()}, Interests: {cloned_object1.get_interests()}")
    print(f"Cloned Object 2: {cloned_object2.get_name()}, Interests: {cloned_object2.get_interests()}")
  • 不难发现这里面多了一个PrototypeFactory(工厂类) ,用于管理多个原型对象,可以注册原型并通过原型创建新对象。工厂使用 clone() 方法来创建对象实例,而不直接使用构造函数

最后

  • 原型模式理解起来应该不算复杂,核心就是拷贝
  • 原型模式往往用于类初始化非常复杂的场景,或者一个对象要被多个修改者操作的场景
  • 原型模式很少单独使用,学会将原型模式结合其他的设计模式一起使用。在项目中要多思考多尝试。
相关推荐
linly121914 分钟前
MATLAB学习笔记目录
笔记·学习·matlab
罗汉松(山水白河)21 分钟前
解除WPS登录限制
windows·经验分享·笔记·学习·wps
YYHYJX1 小时前
C#学习笔记 --- 简单应用
开发语言·学习·c#
Clockwiseee1 小时前
JAVA多线程学习
java·开发语言·学习
power-辰南1 小时前
设计模式之原型模式
原型模式
A懿轩A2 小时前
C/C++ 数据结构与算法【排序】 常见7大排序详细解析【日常学习,考研必备】带图+详细代码
c语言·c++·学习·排序算法·排序
JINGWHALE12 小时前
设计模式 行为型 备忘录模式(Memento Pattern)与 常见技术框架应用 解析
前端·人工智能·后端·设计模式·性能优化·系统架构·备忘录模式
zhulangfly2 小时前
【Java设计模式-4】策略模式,消灭if/else迷宫的利器
java·设计模式·策略模式
Nil_cxc2 小时前
机器学习周报-GNN模型学习
人工智能·学习·机器学习
隼玉3 小时前
【STM32-学习笔记-9-】SPI通信
c语言·笔记·stm32·学习