• 设计模式——5. 原型模式


    1. 说明

    原型模式(Prototype Pattern)是一种创建型设计模式,其核心思想是通过复制(克隆)一个现有对象来创建新的对象,而不是通过实例化类来创建。这意味着在原型模式中,新对象的创建不需要知道具体的类,而是通过复制现有对象的属性和状态来创建。原型模式通常包括一个原型接口或抽象类,以及具体的原型类实现该接口或继承该抽象类。

    关键特点和概念:

    1. 原型接口或抽象类(Prototype):定义了复制自身的方法,通常包括一个 clone 方法。
    2. 具体原型类(ConcretePrototype):实现了原型接口或继承了原型抽象类,并提供了具体的克隆方法。这个类的对象可以被复制以创建新的对象。
    3. 客户端(Client):通过请求原型对象来复制新对象的客户端代码。

    原型模式有一些注意事项:

    • 需要确保被克隆的对象是可复制的,即对象的类必须实现克隆方法或接口。
    • 克隆对象可能需要处理对象的内部状态,以确保对象的复制是正确的。

    总之,原型模式是一种有用的设计模式,适用于需要创建对象副本的情况,它通过克隆现有对象来实现创建,提高了效率并降低了复杂性。

    2. 使用的场景

    以下是原型模式使用的场景:

    1. 创建成本高昂的对象: 当创建对象的成本较高,例如需要进行大量的计算、数据库查询、网络请求或其他耗时操作时,使用原型模式可以通过复制现有对象来提高性能,而不必重新计算或重新获取数据。
    2. 复杂对象的创建: 当对象的构造过程非常复杂,包括多个步骤和设置多个属性时,原型模式可以让您避免编写冗长的构造函数,只需复制现有对象并稍微调整属性即可。
    3. 对象初始化复杂: 当对象需要进行复杂的初始化工作,例如读取配置文件、连接数据库或进行身份验证等操作时,原型模式可以复制一个已初始化的对象,而不必重新执行初始化逻辑。
    4. 对象的多个变体: 如果需要创建对象的多个变体或配置,而这些变体仅有少量属性不同,原型模式可以通过复制一个原型对象并修改其差异属性来创建这些变体。
    5. 对象的深拷贝: 原型模式可以实现对象的深拷贝,即复制对象及其关联对象的所有内容,而不仅仅是浅拷贝。这对于复杂的数据结构非常有用。
    6. 动态配置对象: 在某些情况下,系统需要根据用户输入或其他条件来配置对象。原型模式允许您创建一个基本配置的原型对象,然后根据需要进行修改。
    7. 对象池: 一些应用程序需要维护一个对象池,以便在需要时获取可重用的对象。原型模式可以用来创建池中的对象。

    总之,原型模式在需要创建对象副本、降低创建成本、提高性能或简化对象创建过程的情况下非常有用。它通过复制现有对象来创建新对象,提供了一种灵活的方式来处理对象的创建和初始化。

    3. 应用例子

    以下是一个使用Python语言实现原型模式的示例,假设我们有一个图形编辑器,需要创建不同类型的图形对象(如圆形和矩形),并且可以复制已有的图形对象来创建新的图形对象:

    import copy
    
    # 创建原型基类
    class ShapePrototype:
        def clone(self):
            return copy.copy(self)
    
    # 创建具体的图形类:圆形
    class Circle(ShapePrototype):
        def __init__(self, radius):
            self.radius = radius
    
        def __str__(self):
            return f"Circle with radius {self.radius}"
    
    # 创建具体的图形类:矩形
    class Rectangle(ShapePrototype):
        def __init__(self, width, height):
            self.width = width
            self.height = height
    
        def __str__(self):
            return f"Rectangle with width {self.width} and height {self.height}"
    
    # 客户端代码
    if __name__ == "__main__":
        # 创建原型对象
        circle_prototype = Circle(5)
        rectangle_prototype = Rectangle(10, 20)
    
        # 复制原型对象来创建新对象
        circle1 = circle_prototype.clone()
        circle2 = circle_prototype.clone()
        rectangle1 = rectangle_prototype.clone()
    
        # 修改复制后的对象的属性
        circle1.radius = 8
        circle2.radius = 10
        rectangle1.width = 15
        rectangle1.height = 25
    
        # 打印对象
        print(circle1)       # 输出: Circle with radius 8
        print(circle2)       # 输出: Circle with radius 10
        print(rectangle1)    # 输出: Rectangle with width 15 and height 25
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这个示例中:

    • ShapePrototype 是原型基类,它包含一个 clone 方法,该方法使用 copy.copy 来复制对象。
    • Circle 和 Rectangle 是具体的图形类,它们继承自 ShapePrototype 并实现了 str 方法以便于打印对象的信息。
    • 客户端代码中,我们创建了两个原型对象 circle_prototype 和 rectangle_prototype,然后使用 clone 方法复制这些原型对象来创建新的图形对象。通过修改复制后的对象的属性,我们可以创建具有不同属性的图形对象。

    这个示例展示了如何使用原型模式创建对象的副本,而不必关心对象创建的细节,从而实现了对象的复用和灵活性。

    4. 实现要素

    原型模式的实现要素包括以下部分:

    1. 原型接口或抽象类(Prototype): 定义了复制自身的方法,通常包括一个 clone 方法,该方法用于创建对象的副本。
    2. 具体原型类(Concrete Prototype): 实现了原型接口或继承了原型抽象类,它包含了复制对象的逻辑,并且允许创建对象的副本。
    3. 客户端(Client): 负责创建和使用原型对象,通常通过原型对象的 clone 方法来创建新的对象副本。

    5. UML图

    以下是原型模式的简化 UML 类图:

    +------------------+
    |   Prototype     |
    +------------------+
    |  +clone(): Prototype   |
    +------------------+
            ^
            |
            |
            |
    +------------------+
    |  ConcretePrototype |
    +------------------+
    |  +clone(): ConcretePrototype |
    +------------------+
            ^
            |
            |
            |
    +------------------+
    |      Client      |
    +------------------+
    |                  |
    |  +createPrototype(): Prototype |
    |                  |
    +------------------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在 UML 类图中:

    • Prototype 是原型接口或抽象类,定义了 clone 方法。
    • ConcretePrototype 是具体原型类,实现了 Prototype 接口,包含了复制对象的逻辑。
    • Client 是客户端类,它通过调用 createPrototype 方法来创建新的对象副本,而不需要直接与具体原型类交互。

    这个 UML 类图反映了原型模式的关键要素和类之间的关系,帮助理解原型模式的结构和工作原理。客户端通过调用原型对象的 clone 方法来复制对象,从而实现对象的创建和复制。

    6. Java/golang/javascrip/C++ 等语言实现方式

    6.1 Java实现

    上述例子用Java语言实现示例如下:

    import java.util.HashMap;
    import java.util.Map;
    
    // 创建原型接口
    interface ShapePrototype {
        ShapePrototype clone();
        String getInfo();
    }
    
    // 创建具体的图形类:圆形
    class Circle implements ShapePrototype {
        private String type;
    
        public Circle(String type) {
            this.type = type;
        }
    
        @Override
        public ShapePrototype clone() {
            return new Circle(this.type);
        }
    
        @Override
        public String getInfo() {
            return "Circle of type " + type;
        }
    }
    
    // 创建具体的图形类:矩形
    class Rectangle implements ShapePrototype {
        private String type;
    
        public Rectangle(String type) {
            this.type = type;
        }
    
        @Override
        public ShapePrototype clone() {
            return new Rectangle(this.type);
        }
    
        @Override
        public String getInfo() {
            return "Rectangle of type " + type;
        }
    }
    
    // 创建原型管理器
    class ShapePrototypeManager {
        private Map shapeMap = new HashMap<>();
    
        public void addShape(String key, ShapePrototype shapePrototype) {
            shapeMap.put(key, shapePrototype);
        }
    
        public ShapePrototype getShape(String key) {
            ShapePrototype shapePrototype = shapeMap.get(key);
            if (shapePrototype != null) {
                return shapePrototype.clone();
            }
            return null;
        }
    }
    
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            // 创建原型管理器
            ShapePrototypeManager manager = new ShapePrototypeManager();
    
            // 添加具体图形原型
            manager.addShape("circle", new Circle("solid"));
            manager.addShape("rectangle", new Rectangle("dotted"));
    
            // 使用原型创建新对象
            ShapePrototype clonedCircle = manager.getShape("circle");
            ShapePrototype clonedRectangle = manager.getShape("rectangle");
    
            // 打印对象信息
            System.out.println(clonedCircle.getInfo());    // 输出: Circle of type solid
            System.out.println(clonedRectangle.getInfo()); // 输出: Rectangle of type dotted
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    6.2 Golang实现

    上述例子用golang实现示例如下:

    package main
    
    import (
            "fmt"
            "sync"
    )
    
    // 创建原型接口
    type ShapePrototype interface {
            Clone() ShapePrototype
            GetInfo() string
    }
    
    // 创建具体的图形类:圆形
    type Circle struct {
            Type string
    }
    
    func (c *Circle) Clone() ShapePrototype {
            return &Circle{Type: c.Type}
    }
    
    func (c *Circle) GetInfo() string {
            return fmt.Sprintf("Circle of type %s", c.Type)
    }
    
    // 创建具体的图形类:矩形
    type Rectangle struct {
            Type string
    }
    
    func (r *Rectangle) Clone() ShapePrototype {
            return &Rectangle{Type: r.Type}
    }
    
    func (r *Rectangle) GetInfo() string {
            return fmt.Sprintf("Rectangle of type %s", r.Type)
    }
    
    // 创建原型管理器
    type ShapePrototypeManager struct {
            prototypes map[string]ShapePrototype
            mu         sync.Mutex
    }
    
    func NewShapePrototypeManager() *ShapePrototypeManager {
            return &ShapePrototypeManager{
                    prototypes: make(map[string]ShapePrototype),
            }
    }
    
    func (m *ShapePrototypeManager) AddShape(key string, prototype ShapePrototype) {
            m.mu.Lock()
            defer m.mu.Unlock()
            m.prototypes[key] = prototype
    }
    
    func (m *ShapePrototypeManager) GetShape(key string) ShapePrototype {
            m.mu.Lock()
            defer m.mu.Unlock()
            prototype, ok := m.prototypes[key]
            if !ok {
                    return nil
            }
            return prototype.Clone()
    }
    
    // 客户端代码
    func main() {
            // 创建原型管理器
            manager := NewShapePrototypeManager()
    
            // 添加具体图形原型
            manager.AddShape("circle", &Circle{Type: "solid"})
            manager.AddShape("rectangle", &Rectangle{Type: "dotted"})
    
            // 使用原型创建新对象
            clonedCircle := manager.GetShape("circle")
            clonedRectangle := manager.GetShape("rectangle")
    
            // 打印对象信息
            fmt.Println(clonedCircle.GetInfo())    // 输出: Circle of type solid
            fmt.Println(clonedRectangle.GetInfo()) // 输出: Rectangle of type dotted
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    6.3 Javascript实现

    上述例子用javascript实现示例如下:

    // 创建原型接口
    class ShapePrototype {
        clone() {}
        getInfo() {}
    }
    
    // 创建具体的图形类:圆形
    class Circle extends ShapePrototype {
        constructor(type) {
            super();
            this.type = type;
        }
    
        clone() {
            return new Circle(this.type);
        }
    
        getInfo() {
            return `Circle of type ${this.type}`;
        }
    }
    
    // 创建具体的图形类:矩形
    class Rectangle extends ShapePrototype {
        constructor(type) {
            super();
            this.type = type;
        }
    
        clone() {
            return new Rectangle(this.type);
        }
    
        getInfo() {
            return `Rectangle of type ${this.type}`;
        }
    }
    
    // 创建原型管理器
    class ShapePrototypeManager {
        constructor() {
            this.prototypes = {};
        }
    
        addShape(key, prototype) {
            this.prototypes[key] = prototype;
        }
    
        getShape(key) {
            const prototype = this.prototypes[key];
            if (prototype) {
                return prototype.clone();
            }
            return null;
        }
    }
    
    // 客户端代码
    const manager = new ShapePrototypeManager();
    
    // 添加具体图形原型
    manager.addShape("circle", new Circle("solid"));
    manager.addShape("rectangle", new Rectangle("dotted"));
    
    // 使用原型创建新对象
    const clonedCircle = manager.getShape("circle");
    const clonedRectangle = manager.getShape("rectangle");
    
    // 打印对象信息
    console.log(clonedCircle.getInfo());    // 输出: Circle of type solid
    console.log(clonedRectangle.getInfo()); // 输出: Rectangle of type dotted
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    6.4 C++实现

    上述例子用C++实现如下:

    #include 
    #include 
    
    // 创建原型接口
    class ShapePrototype {
    public:
        virtual ShapePrototype* clone() const = 0;
        virtual std::string getInfo() const = 0;
    };
    
    // 创建具体的图形类:圆形
    class Circle : public ShapePrototype {
    private:
        std::string type;
    
    public:
        Circle(const std::string& type) : type(type) {}
    
        ShapePrototype* clone() const override {
            return new Circle(*this);
        }
    
        std::string getInfo() const override {
            return "Circle of type " + type;
        }
    };
    
    // 创建具体的图形类:矩形
    class Rectangle : public ShapePrototype {
    private:
        std::string type;
    
    public:
        Rectangle(const std::string& type) : type(type) {}
    
        ShapePrototype* clone() const override {
            return new Rectangle(*this);
        }
    
        std::string getInfo() const override {
            return "Rectangle of type " + type;
        }
    };
    
    // 创建原型管理器
    class ShapePrototypeManager {
    private:
        std::unordered_map prototypes;
    
    public:
        void addShape(const std::string& key, ShapePrototype* prototype) {
            prototypes[key] = prototype;
        }
    
        ShapePrototype* getShape(const std::string& key) const {
            auto it = prototypes.find(key);
            if (it != prototypes.end()) {
                return it->second->clone();
            }
            return nullptr;
        }
    };
    
    // 客户端代码
    int main() {
        // 创建原型管理器
        ShapePrototypeManager manager;
    
        // 添加具体图形原型
        manager.addShape("circle", new Circle("solid"));
        manager.addShape("rectangle", new Rectangle("dotted"));
    
        // 使用原型创建新对象
        ShapePrototype* clonedCircle = manager.getShape("circle");
        ShapePrototype* clonedRectangle = manager.getShape("rectangle");
    
        // 打印对象信息
        if (clonedCircle) {
            std::cout << clonedCircle->getInfo() << std::endl;    // 输出: Circle of type solid
        }
        if (clonedRectangle) {
            std::cout << clonedRectangle->getInfo() << std::endl; // 输出: Rectangle of type dotted
        }
    
        // 释放内存
        delete clonedCircle;
        delete clonedRectangle;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    7. 练习题

    设计一个电子设备控制器,其中有多种不同类型的遥控器按钮。每个按钮可以控制一种特定类型的设备,例如电视、音响、灯等。当用户按下按钮时,设备应该启动并执行相应的操作。使用原型模式设计一个控制器,以便用户可以自定义按钮的功能,并创建多个相似的按钮,每个按钮都可以独立控制一个设备。

    要求:

    1. 创建一个抽象设备控制器原型类(DeviceControllerPrototype),其中包含 clone 方法和执行操作的抽象方法。
    2. 创建具体的设备控制器类(如TVController、AudioController、LightController),它们继承自抽象设备控制器原型类,实现具体的操作方法。
    3. 创建一个设备控制器管理器类,用于存储和获取不同类型的设备控制器原型对象。
    4. 客户端代码应该能够从设备控制器管理器中获取不同类型的设备控制器,并根据用户的需求创建按钮并执行相应的操作。

    你可以在评论区里或者私信我回复您的答案,这样我或者大家都能帮你解答,期待着你的回复~

  • 相关阅读:
    9年前,我的第一份实习工作
    15-Linux之源码包安装软件
    sudo apt update 后会出现的一堆问题的解决
    户外旅行摄影手册,旅游摄影完全攻略
    ES 客户端 RestHighLevelClient Connection reset by peer 亲测有效 2022-11-05
    OpenAI 董事会宫斗始作俑者?一窥伊尔亚·苏茨克维内心世界
    计算机毕业设计springboot基于springboot的游戏交易网络无忧3op09源码+系统+程序+lw文档+部署
    SpringMVC概述及入门
    Small RTOS51 学习笔记(8)信号量
    轨迹数据能够提取哪些特征?
  • 原文地址:https://blog.csdn.net/guohuang/article/details/133325180