技术成神之路:设计模式(三)原型模式

1. 定义


原型模式(Prototype Pattern)是一种创建型设计模式,旨在通过复制现有对象来创建新对象,而不是通过实例化类的方式。这个模式可以提高对象创建的效率,尤其是在创建对象的过程非常复杂或代价高昂时。

2. 结构


原型模式包含以下角色:

  • Prototype(原型接口):用于声明克隆自身的方法。通常这个接口会定义一个名为clone的抽象方法。
  • ConcretePrototype(具体原型类):实现原型接口,并实现克隆自身的方法。这类对象可以被克隆。
  • Client(客户端):使用原型接口来克隆新的对象。

UML类图:

3. 示例代码


java 复制代码
// 原型接口
interface Prototype extends Cloneable {
    Prototype clone();
}

// 具体原型类A
class ConcretePrototypeA implements Prototype {
    private String name;

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

    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String toString() {
        return "ConcretePrototypeA{name='" + name + "'} hashcode= "+ hashCode();
    }
}

// 具体原型类B
class ConcretePrototypeB implements Prototype {
    private int value;

    public ConcretePrototypeB(int value) {
        this.value = value;
    }

    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String toString() {
        return "ConcretePrototypeB{value=" + value + "} hashcode= "+ hashCode();
    }
}

测试:

java 复制代码
@Test
    public void test() {
        ConcretePrototypeA prototypeA = new ConcretePrototypeA("Prototype A");
        ConcretePrototypeB prototypeB = new ConcretePrototypeB(42);

        Prototype clonedPrototypeA = prototypeA.clone();
        Prototype clonedPrototypeB = prototypeB.clone();

        System.out.println("原型A: "+prototypeA);
        System.out.println("克隆A: "+clonedPrototypeA);
        System.out.println("原型B: "+prototypeB);
        System.out.println("克隆B: "+clonedPrototypeB);
    }

打印:

原型A: ConcretePrototypeA{name='Prototype A'} hashcode= 1823541245
克隆A: ConcretePrototypeA{name='Prototype A'} hashcode= 1020154737
原型B: ConcretePrototypeB{value=42} hashcode= 398457879
克隆B: ConcretePrototypeB{value=42} hashcode= 1850954068

4. 应用场景


  • 对象的创建开销很大:通过克隆现有对象而不是重新创建,可以节省时间和资源。
  • 系统需要大量类似对象 :通过克隆原型对象,可以快速生成多个相似但独立的对象。
  • 对象的状态需要动态改变:通过克隆原型对象,可以创建具有特定状态的新对象。

情景回顾:

原型模式在实际应用中可能并不常见,或许你见到过但没留意,因为它的应用场景太少了,让我想起了在写一个多任务下载模块时,每下载一个文件其都有对应的mode,记录一些下载信息状态信息等内容,再进行更新进度的时候需要把这个对象发送出去,通知外界更新UI,有一个问题就是下载中操作的对象和发送出去的对象是同一个,就会出现异常现象,我发送出去的下载进度是90%,UI还没来得及更新,这边又将进度修改为95%了,emm... 可能我描述的问题,你觉的不严重,但这种不可预测的现象是我们不希望发生的。

其中解决方式一 就是克隆一个对象,让UI显示的和下载操作的对象互不干扰,这时如果你new一个新对象的话相比克隆就劣势就凸显出来了。

5. 优缺点


优点:

  • 提高对象创建效率:避免了复杂对象的重复创建,通过克隆现有对象来生成新对象。
  • 动态创建对象:可以在运行时动态创建对象,而无需了解具体的类。
  • 减少子类的数量:通过克隆原型对象,可以减少创建子类的数量,增强系统的灵活性。

缺点:

  • 深拷贝和浅拷贝问题:在涉及复杂对象时,深拷贝和浅拷贝的问题需要特别注意。如果对象包含对其他对象的引用,浅拷贝可能不够用,需要实现深拷贝。
  • 克隆方法的实现复杂:对于一些复杂的对象,克隆方法的实现可能比较复杂,需要处理对象间的依赖关系。

6. 深拷贝与浅拷贝


在原型模式中,克隆可以分为浅拷贝和深拷贝:

  • 浅拷贝:复制对象时,只复制对象本身,而不复制对象所引用的其他对象。也就是说,复制后的对象与原对象共享对其他对象的引用。
  • 深拷贝:复制对象时,不仅复制对象本身,还复制对象所引用的其他对象。这样,复制后的对象与原对象是完全独立的,不共享任何引用。

7. 深拷贝与浅拷贝示例


java 复制代码
// 原型接口
interface Prototype extends Cloneable {
    Prototype clone();
}

// 具体原型类
class ConcretePrototype implements Prototype {
    private String name;
    private List<String> list;

    public ConcretePrototype(String name) {
        this.name = name;
        this.list = new ArrayList<>();
    }

    public void addToList(String item) {
        list.add(item);
    }

    public List<String> getList() {
        return list;
    }

    @Override
    public Prototype clone() {
        try {
            ConcretePrototype copy = (ConcretePrototype) super.clone();
            // 深拷贝 -测试浅拷贝时注释下面代码!!!
            copy.list = new ArrayList<>(this.list);
            return copy;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String toString() {
        return "ConcretePrototype{name='" + name + "', list=" + list + "} list hashcode=" + list.hashCode();
    }
}

测试:

cpp 复制代码
    @Test
    public void test() {
        ConcretePrototype prototype = new ConcretePrototype("Prototype");
        prototype.addToList("Item1");
        prototype.addToList("Item2");

        // 浅拷贝示例
        ConcretePrototype shallowClone = (ConcretePrototype) prototype.clone();

        // 添加新项到原型对象的列表
        prototype.addToList("Item3");

        System.out.println("原型: " + prototype);
        System.out.println("浅拷贝: " + shallowClone);

        // 深拷贝示例
        ConcretePrototype deepClone = (ConcretePrototype) prototype.clone();

        // 添加新项到深拷贝对象的列表
        deepClone.addToList("Item4");

        System.out.println("原型: " + prototype);
        System.out.println("深拷贝: " + deepClone);
    }

测试浅拷贝打印:

原型: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3]} list hashcode=1757018142
浅拷贝: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3]} list hashcode=1757018142

可以看出两个对象所引用的list对象为同一个

测试深拷贝打印:

原型: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3]} list hashcode=1757018142
深拷贝: ConcretePrototype{name='Prototype', list=[Item1, Item2, Item3, Item4]} list hashcode=-1296039165

两个对象引用的list完全不一样了,操作互不影响

8. 设计模式的比较


原型模式与其他创建型设计模式(如工厂模式、抽象工厂模式、单例模式等)有其独特之处:

  • 与工厂模式的区别:工厂模式通过提供一个方法来创建对象,而原型模式通过复制现有对象来创建新的对象。工厂模式适合对象创建过程简单但需要解耦对象创建过程的场景,而原型模式适合对象创建过程复杂且需要高效创建对象的场景。
  • 与单例模式的区别:单例模式确保一个类只有一个实例,而原型模式则允许通过克隆来创建多个实例。它们解决的问题不同,前者关注的是实例的唯一性,后者关注的是高效创建对象。

9. 结论


原型模式是一种高效的对象创建模式,它通过克隆现有对象来创建新对象,避免了通过构造函数创建对象的高昂代价,尽管原型模式在许多方面具有优势,但在实现过程中需要注意对象间的引用关系,确保深拷贝和浅拷贝的正确实现,以避免不必要的资源浪费和潜在的错误。

相关推荐
lxyzcm6 小时前
深入理解C++23的Deducing this特性(上):基础概念与语法详解
开发语言·c++·spring boot·设计模式·c++23
越甲八千6 小时前
重温设计模式--单例模式
单例模式·设计模式
Vincent(朱志强)6 小时前
设计模式详解(十二):单例模式——Singleton
android·单例模式·设计模式
诸葛悠闲8 小时前
设计模式——桥接模式
设计模式·桥接模式
捕鲸叉12 小时前
C++软件设计模式之外观(Facade)模式
c++·设计模式·外观模式
小小小妮子~12 小时前
框架专题:设计模式
设计模式·框架
先睡12 小时前
MySQL的架构设计和设计模式
数据库·mysql·设计模式
小马哥编程18 小时前
原型链(Prototype Chain)入门
css·vue.js·chrome·node.js·原型模式·chrome devtools
Damon_X20 小时前
桥接模式(Bridge Pattern)
设计模式·桥接模式
越甲八千1 天前
重温设计模式--享元模式
设计模式·享元模式