【设计模式系列笔记】原型模式

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 原型模式(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制现有对象来创建新对象,而无需知道其具体类型。这种模式属于对象创建型模式,通过克隆来避免使用new关键字创建对象,提高性能和降低系统的耦合度。

1、原型模式介绍

原型模式(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制现有对象来创建新对象,而无需知道其具体类型。这种模式属于对象创建型模式,通过克隆来避免使用new关键字创建对象,提高性能和降低系统的耦合度。

在Java中,原型模式的实现通常依赖于Cloneable接口和clone()方法。Cloneable接口标识一个类可以通过克隆创建对象。原型模式的关键是要实现对象的克隆,这可以通过浅克隆或深克隆来完成,具体取决于对象内部是否包含了引用类型。

2、关键思想

  1. 对象复制: 原型模式通过复制现有对象的数据来创建新对象,而不是通过使用 new 关键字直接实例化一个新对象。这种复制可以是浅复制(shallow copy)或深复制(deep copy),具体取决于对象内部是否包含引用类型
  1. 浅复制(Shallow Copy):
  • 浅复制仅复制对象本身的所有字段,而不会复制引用类型的对象。
  • 如果原型对象内部包含引用类型的字段,复制的结果是原始对象和副本对象引用相同的引用类型对象,而不是复制一份引用类型对象。
  • 原始对象和副本对象之间共享引用类型对象,因此对引用类型对象的修改会在两者之间产生影响。
  1. 深复制(Deep Copy):
  • 深复制不仅复制对象本身的所有字段,还会递归复制引用类型的对象,使得原始对象和副本对象引用不同的引用类型对象。
  • 原始对象和副本对象之间不共享引用类型对象,因此对引用类型对象的修改不会影响另一个对象。
  1. Cloneable 接口: 在Java中,被复制的对象通常需要实现 Cloneable 接口,该接口标识了对象是可复制的。这个接口是一个标记接口,表示该类的对象可以通过 clone() 方法进行复制。
  2. clone() 方法: 被复制的对象需要重写 clone() 方法,该方法负责实现对象的复制逻辑。在复制过程中,可以选择是进行浅复制还是深复制,以满足具体需求。
  3. 克隆和原型的独立性: 原型模式创建的新对象和原始对象是相互独立的。对新对象的修改不会影响到原始对象,反之亦然。这是通过复制对象数据而不是共享引用来实现的。
  4. 动态配置对象: 原型模式允许动态配置对象,因为在运行时可以创建对象的克隆,并根据实际需求进行调整。

原型模式的优势在于它能够提高系统性能,避免了重复创建相似对象的开销,同时减少了对具体类的依赖,降低了系统的耦合度。该模式常用于需要大量相似对象的场景,特别是当对象的创建过程较为复杂时。

3、实现方式:

假设我们有一个游戏角色类 GameCharacter,它包含一些基本属性,如角色名称和武器列表。我们将使用原型模式创建角色的克隆,以便在游戏中动态生成相似的角色。以下是一个的实现例子:

示例代码

import java.util.ArrayList;
import java.util.List;
// 步骤1:定义可克隆的原型类
class GameCharacter implements Cloneable {
    private String name; // 角色名称
    private List<String> weapons; // 武器列表
    // 构造方法
    public GameCharacter(String name) {
        this.name = name;
        this.weapons = new ArrayList<>();
    }
    // 添加武器
    public void addWeapon(String weapon) {
        weapons.add(weapon);
    }
    // 打印角色信息
    public void displayInfo() {
        System.out.println("Character: " + name);
        System.out.println("Weapons: " + weapons);
    }
    // 步骤2:重写clone()方法
    @Override
    public GameCharacter clone() throws CloneNotSupportedException {
        // 浅复制
        GameCharacter clonedCharacter = (GameCharacter) super.clone();
        // 深复制武器列表
        clonedCharacter.weapons = new ArrayList<>(this.weapons);
        return clonedCharacter;
    }
}
// 步骤3:使用原型创建对象
public class PrototypeExample {
    public static void main(String[] args) {
        // 创建原型角色
        GameCharacter originalCharacter = new GameCharacter("Hero");
        originalCharacter.addWeapon("Sword");
        originalCharacter.addWeapon("Shield");
        // 打印原始角色信息
        System.out.println("Original Character:");
        originalCharacter.displayInfo();
        try {
            // 克隆角色
            GameCharacter clonedCharacter = originalCharacter.clone();
            // 添加新武器到克隆角色
            clonedCharacter.addWeapon("Bow");
            // 打印克隆角色信息
            System.out.println("\nCloned Character:");
            clonedCharacter.displayInfo();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,我们创建了一个 GameCharacter 类,它具有名称和武器列表属性。通过实现 Cloneable 接口和重写 clone() 方法,我们使该类成为可克隆的原型。在 main 方法中,我们创建了一个原始角色对象,然后通过克隆创建了一个相似的角色对象。这两个角色对象共享相同的名称,但武器列表是相互独立的,即实现了深复制。

要点:

  1. 克隆方法: 原型模式的核心是在原型类中实现 Cloneable 接口,并重写 clone() 方法,确保对象可以被复制。
  2. 浅复制和深复制: 根据实际需求选择浅复制或深复制。浅复制只复制对象本身,而深复制会递归复制对象的所有引用类型成员。
  3. 性能提升: 原型模式可以在一定程度上提升系统性能,因为通过复制对象避免了对象的重新创建,尤其在对象的创建过程较为复杂时更为显著。
  4. 动态配置对象: 原型模式允许动态配置对象,因为可以在运行时通过克隆创建新对象,而无需知道具体类型。
  5. 适用于大对象: 当对象的创建过程较为复杂、耗时或者对象的复制是一种常见操作时,原型模式是一个很好的选择。

注意事项:

  1. 深复制的实现: 如果对象内部包含引用类型成员,确保进行深复制,以防止克隆对象和原始对象共享引用类型对象。
  2. 克隆方法的调用: 在使用原型模式时,要注意正确调用对象的 clone() 方法,最好通过捕获 CloneNotSupportedException 来处理可能的异常。
  3. 构造方法的调用: 在克隆时,对象的构造方法不会被调用。如果需要执行特定的初始化操作,可以在 clone() 方法中手动进行。
  4. 序列化替代方案: 在某些情况下,使用序列化(Serializable)和反序列化来实现对象的复制可能是更合适的替代方案。
  5. 克隆和单例模式: 原型模式和单例模式可能存在一些冲突,因为单例模式通常要求只有一个实例,而原型模式则是通过克隆创建新实例。在这种情况下,可以考虑使用其他创建型设计模式,如工厂模式。

优点:

  1. 性能提升: 原型模式通过复制现有对象避免了对象的重新创建,可以提高系统性能,特别是在对象的创建过程较为复杂或者耗时的情况下。
  2. 动态配置对象: 克隆操作可以在运行时动态配置对象,而不是在编译时确定对象的类型。这使得系统更加灵活,能够根据实际需要动态创建对象。
  3. 简化对象创建: 原型模式使得对象的创建变得简单,不需要知道具体对象的类型,只需复制一个现有对象即可得到新对象。
  4. 减少对具体类的依赖: 客户端可以通过克隆操作而不是直接实例化对象,从而减少对具体类的依赖,提高系统的灵活性。

缺点:

  1. 深复制实现复杂: 如果对象内部包含引用类型成员,实现深复制可能相对复杂,需要递归复制所有引用类型对象及其内部对象。
  2. 需要实现Cloneable接口: 被克隆的类需要实现Cloneable接口,并重写clone()方法,这违反了依赖倒置原则(Dependency Inversion Principle)。
  3. 克隆方法的调用: 在使用原型模式时,要注意正确调用对象的clone()方法,需要处理可能的CloneNotSupportedException异常。

应用场景:

  1. 大量相似对象的创建: 当需要创建大量相似对象,而且这些对象的区别仅在于其属性值时,原型模式是一个很好的选择,可以通过克隆来创建新对象,避免重复的初始化工作。
  2. 动态配置对象: 当需要动态配置对象而不知道具体类型时,原型模式提供了一种灵活的创建对象的方式。
  3. 对象的创建过程复杂或耗时: 如果对象的创建过程包含了复杂的初始化步骤或者是耗时的操作,使用原型模式可以提高系统性能。
  4. 避免构造函数的约束: 在某些情况下,构造函数可能有一些限制,而通过克隆可以避免这些约束,使得对象的创建更加灵活。

总的来说,原型模式在某些场景下是非常有用的,特别是当需要创建大量相似对象或者对象创建过程较为复杂的情况。在使用时需要注意深复制的实现和克隆方法的调用。

目录
相关文章
|
8天前
|
设计模式 Java
【设计模式系列笔记】责任链模式
责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理它。每个处理者都有一个对下一个处理者的引用。责任链模式常用于处理请求的场景,例如在一个请求需要经过多个步骤或者多个对象来处理的情况下。
23 0
|
8天前
|
设计模式 缓存 监控
【设计模式系列笔记】代理模式
代理模式是一种结构型设计模式,它允许一个对象(代理对象)控制另一个对象的访问。代理对象通常充当客户端和实际对象之间的中介,用于对实际对象的访问进行控制、监控或其他目的。
43 1
|
8天前
|
设计模式
【设计模式】张一鸣笔记:责任链接模式怎么用?
【设计模式】张一鸣笔记:责任链接模式怎么用?
12 1
|
8天前
|
设计模式 算法 Java
【设计模式系列笔记】设计模式与设计原则
设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 设计原则是一些通用的设计指导方针,它们提供了如何设计一个优秀的软件系统的基本思想和规则。指导着设计者如何组织代码以实现高内聚、低耦合、易扩展和易维护的软件系统。
26 4
|
8天前
|
设计模式 JavaScript 前端开发
vue的设计模式_笔记
vue的设计模式_笔记
16 0
|
8天前
|
设计模式 算法 编译器
【设计模式系列笔记】访问者模式
访问者模式是一种行为设计模式,旨在将算法与对象结构分离,使得能够在不修改元素类的前提下定义新的操作。这一模式的核心思想是在元素类中添加一个接受访问者的方法,从而实现在不同元素上执行不同操作的能力。
33 0
|
8天前
|
设计模式 SQL 算法
【设计模式系列笔记】模板方法模式
模板方法模式是一种行为设计模式,它定义了一个算法的骨架,并允许子类在不改变该算法结构的情况下重新定义算法的某些步骤。这种模式属于行为型模式,它通过将算法的不同部分封装在不同的方法中,从而使子类能够在不改变算法结构的前提下定制算法的某些步骤。
33 0
|
8天前
|
设计模式 算法 Java
【设计模式系列笔记】策略模式
策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列的算法,将每个算法封装起来,并且使它们可以互相替换。策略模式使得算法可以独立于客户端而变化。
27 0
|
8天前
|
设计模式 Java
【设计模式系列笔记】状态模式
在Java中,状态模式是一种行为设计模式,它允许对象在其内部状态改变时改变其行为。状态模式的关键思想是将对象的状态封装成独立的类,并将对象的行为委托给当前状态的对象。这样,当对象的状态发生变化时,其行为也会相应地发生变化。
25 0
|
8天前
|
设计模式 消息中间件 存储
【设计模式系列笔记】观察者模式
观察者模式是一种设计模式,它允许一个对象(主题)维护一组依赖于它的对象(观察者)并在状态发生变化时通知它们。这种模式属于行为型模式。在观察者模式中,主题是被观察的对象,而观察者是依赖于主题的对象,当主题的状态发生变化时,所有注册的观察者都会得到通知并自动更新。
24 0