设计模式-原型模式

1. 概念

  • 原型模式是一种创建型设计模式,它通过复制(克隆)一个现有的对象来创建新的对象,而不是通过调用构造函数的方式。

2. 原理结构图

  • 原理结构图说明
    • 原型接口(Prototype):定义了复制方法的接口,通常由 Cloneable 接口实现。
    • 具体原型(ConcretePrototype):实现原型接口的类,提供具体的复制方法。
    • 客户端(Client):使用具体原型类的实例来创建新的对象。

3. 代码示例

3.1 示例1
  • 简单的Java原型模式代码示例
java 复制代码
// 创建一个实现了Cloneable接口的抽象类
public abstract class Prototype implements Cloneable {
    private String name;

    public Prototype(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 重写clone()方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

// 创建一个具体的原型类
public class ConcretePrototype extends Prototype {
    public ConcretePrototype(String name) {
        super(name);
    }
}

// 测试类
public class Test {
    public static void main(String[] args) {
        // 创建一个原型对象
        Prototype prototype = new ConcretePrototype("原型对象");

        // 使用clone()方法创建新对象
        try {
            Prototype clonedPrototype = (Prototype) prototype.clone();
            System.out.println("原型对象:" + prototype.getName());
            System.out.println("克隆对象:" + clonedPrototype.getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

3.2 示例二
  • 实例代码
java 复制代码
abstract class BasketballPrototype {
    protected String brand;
    protected String desc;
    protected double weight;
    protected double perimeter;

    public BasketballPrototype(String brand, String desc, double weight, double perimeter) {
        this.brand = brand;
        this.desc = desc;
        this.weight = weight;
        this.perimeter = perimeter;
    }

    @Override
    public abstract BasketballPrototype clone();
}

class Spalding extends BasketballPrototype {

    public Spalding(String brand, String desc, double weight, double perimeter) {
        super(brand, desc, weight, perimeter);
    }

    @Override
    public BasketballPrototype clone() {
        System.out.printf("生产 Spalding: %s %s %s %s\n", this.brand, this.desc, this.weight, this.perimeter);
        return new Spalding(this.brand, this.desc, this.weight, this.perimeter);
    }
}

class Molten extends BasketballPrototype {

    public Molten(String brand, String desc, double weight, double perimeter) {
        super(brand, desc, weight, perimeter);
    }

    @Override
    public BasketballPrototype clone() {
        System.out.printf("生产 Molten: %s %s %s %s\n", this.brand, this.desc, this.weight, this.perimeter);
        return new Molten(this.brand, this.desc, this.weight, this.perimeter);
    }
}

class BasketballPrototypeManager {
    private static Hashtable<String, BasketballPrototype> basketballPrototypeMap = new Hashtable<>();

    public static BasketballPrototype get(String type) {
        BasketballPrototype basketballPrototype = basketballPrototypeMap.get(type);
        return basketballPrototype.clone();
    }

    public static void buildProtypeList() {
        Spalding spalding = new Spalding("Spalding", "通用性比较强,适合室内外使用", 600, 75);
        basketballPrototypeMap.put("Spalding", spalding);
        Molten molten = new Molten("Molten", "独特的外观和优秀的性能", 610, 80);
        basketballPrototypeMap.put("Molten", molten);
    }
}

public class BasketballFactoryTest {

    public static void main(String[] args) {
        BasketballPrototypeManager.buildProtypeList();
        for (int i = 0; i < 8; i++) {
            BasketballPrototypeManager.get("Spalding");
            BasketballPrototypeManager.get("Molten");
        }
    }
}

4. 优缺点

  • 优点
    • 性能提升:通过复制已有对象来创建新对象,通常比创建全新的对象更快。
    • 减少数据库调用:可以缓存对象,在下一个请求时返回它的克隆,需要时更新数据库,从而减少数据库调用次数。
    • 简化创建过程:不需要知道具体的类,只需要一个现有的实例就可以创建新对象。
    • 动态加载:可以在运行时增加或减少属性,使得对象更加灵活。
  • 缺点
    • 深拷贝问题:如果对象中的字段是引用类型,简单的复制可能会导致所有克隆的对象共享相同的引用,这可能不是预期的行为。
    • 内存占用:每个克隆的对象都会占用额外的内存,尤其是在大量克隆时,可能导致内存消耗过大。
    • 实现复杂性:正确实现原型模式可能需要重写clone()方法,并处理复杂的引用关系,这可能会使代码变得复杂。

5. 应用场景

  • 资源密集型类初始化:如果类的初始化过程消耗资源过多,例如加载大型位图或初始化复杂数据结构,使用原型模式可以避免每次创建新对象时都进行昂贵的初始化操作。
  • 大量相似对象生成:当需要生成大量相似的对象时,原型模式可以通过复制现有对象来减少构造函数的调用次数,从而提高性能。
  • 动态对象创建:在运行时需要根据不同情况创建不同类型的对象时,原型模式可以提供一种灵活的方式来实现对象的动态创建,而不需要预先定义所有可能的对象类型。
  • 避免重复代码:当多个类具有相同的创建逻辑时,可以使用原型模式来避免重复编写相同的代码,而是通过克隆现有对象来实现。
  • 自定义对象创建过程:如果需要在创建对象时加入特定的逻辑或者状态,原型模式允许在克隆过程中对这些逻辑或状态进行定制。

6. JDK中的使用

  • 集合类框架:在Java的集合类框架中,例如ArrayList、HashMap等,当需要创建新的集合对象时,可以通过实现Cloneable接口并重写clone()方法来复制现有的集合对象,从而创建新的对象。
  • 序列化机制:在Java的序列化机制中,通过序列化一个对象,可以创建一个该对象的副本。反序列化过程实际上就是通过已有的对象状态创建新对象的过程,这与原型模式的思想相符。

7. 注意事项

  • 浅拷贝与深拷贝:理解浅拷贝和深拷贝的区别。浅拷贝只复制对象本身和其包含的基本类型字段,而深拷贝则递归地复制对象及其引用的所有对象。
  • 避免循环引用:在实现深拷贝时,要注意避免对象间的循环引用,否则可能导致无限递归的问题。
  • 性能考虑:深拷贝可能涉及复杂的对象图和多次复制操作,可能会对性能产生影响,因此需要根据具体情况权衡是否使用深拷贝。
  • 安全性:在某些情况下,可能需要限制克隆操作,以保护对象的状态不被未授权的修改。可以通过将 clone() 方法声明为 protected 或 package-private 来实现。
  • 客户端使用:客户端应通过具体原型类的 clone() 方法来创建新对象,而不是直接调用构造函数。
相关推荐
CocoaAndYy24 分钟前
设计模式-单例模式
单例模式·设计模式
一颗花生米。2 小时前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
bobostudio19952 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
ok!ko6 小时前
设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
java·设计模式·原型模式
拉里小猪的迷弟7 小时前
设计模式-创建型-常用:单例模式、工厂模式、建造者模式
单例模式·设计模式·建造者模式·工厂模式
严文文-Chris9 小时前
【设计模式-中介者模式】
设计模式·中介者模式
刷帅耍帅9 小时前
设计模式-中介者模式
设计模式·中介者模式
刷帅耍帅10 小时前
设计模式-组合模式
设计模式·组合模式
凌不了云10 小时前
原型模式(prototype)
原型模式
刷帅耍帅11 小时前
设计模式-命令模式
设计模式·命令模式