设计模式原型模式

Posted Kant101

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式原型模式相关的知识,希望对你有一定的参考价值。

1. 概述

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式是实现一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
 
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

 

2. UML图

原型模式的核心就是原型类 ProtoType,ProtoType 类需要具备以下两个条件:

  • (1) 实现 Cloneable 接口:在 Java 中 Cloneable 接口的作用就是在运行时通知虚拟机可以安全地在实现了 Cloneable 接口的类上使用 clone() 方法,只有在实现了 Cloneable 接口的类才可以被拷贝,否则在运行时会抛出 CloneNotSupportedException 异常;
  • (2) 重写 Object 类中的 clone() 方法:在 Java 中所有的父类都是 Object,Object中有一个 clone() 方法用于返回对象的拷贝,但是其作用域是 protected,一般的类无法调用,因此,ProtoType类需要将 clone() 方法的作用域修改为 public;

原型模式是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式。在实际应用中,原型模式很少单独出现,经常与其他模式混用,它的原型类Prototype 也常用抽象类来替代。

 

3. 代码与测试

Prototype

package com.design.pattern.prototype;

/**
 * @author albert.tan
 * @date 2022/11/23
 */
public abstract class Prototype implements Cloneable 

    protected OtherObject otherObject = new OtherObject(123456789L);

    @Override
    protected Object clone() throws CloneNotSupportedException 
        return super.clone();
    

    public abstract void show();

OtherObject

package com.design.pattern.prototype;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * @author albert.tan
 * @date 2022/11/23
 */
@Data
@AllArgsConstructor
public class OtherObject implements Cloneable 

    private Long id;

    @Override
    protected Object clone() throws CloneNotSupportedException 
        return super.clone();
    

ConcretePrototype

package com.design.pattern.prototype;

/**
 * @author albert.tan
 * @date 2022/11/23
 */
public class ShallowClone extends Prototype 

    @Override
    protected Object clone() throws CloneNotSupportedException 
        Prototype prototype = null;
        try 
            prototype = (Prototype) super.clone();
         catch (CloneNotSupportedException e) 
            e.printStackTrace();
        
        return prototype;
    

    @Override
    public void show() 
        System.out.println("浅克隆");
    

package com.design.pattern.prototype;


/**
 * @author albert.tan
 * @date 2022/11/23
 */
public class DeepClone extends Prototype 

    @SuppressWarnings("unchecked")
    @Override
    protected Prototype clone() throws CloneNotSupportedException 
        Prototype prototype = null;
        try 
            prototype = (Prototype) super.clone();
         catch (CloneNotSupportedException e) 
            e.printStackTrace();
        
        if (prototype == null) return null;
        // 递归调用 clone() 方法克隆 Prototype 中的引用类成员
        prototype.otherObject = (OtherObject) this.otherObject.clone();
        return prototype;
    

    @Override
    public void show() 
        System.out.println("深克隆");
    

测试

package com.design.pattern.prototype;

/**
 * @author albert.tan
 * @date 2022/11/23
 */
public class Client 
    public static void main(String[] args) throws CloneNotSupportedException 
        ShallowClone obj1 = new ShallowClone();
        ShallowClone obj2 = (ShallowClone) obj1.clone();
        System.out.println("obj1 == obj2? " + (obj1 == obj2));
        obj2.show();
        System.out.println(obj1.otherObject == obj2.otherObject);

        System.out.println("========================");

        DeepClone obj3 = new DeepClone();
        DeepClone obj4 = (DeepClone) obj3.clone();
        System.out.println("obj3 == obj4? " + (obj3 == obj4));
        obj4.show();
        System.out.println(obj3.otherObject == obj4.otherObject);
    

 

 

4. 运用场景与注意事项

优点与适用场景

(1) 原型模式比 new 方法创建对象的性能要好得多,因为 Object 类的 clone() 方法是一个本地方法,直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显;

(2) 简化对象的创建
所以原型模式适合在重复地创建相似对象的场景使用,比如在一个循环体内创建对象,加入对象创建过程比较复杂或者循环次数很多的话,使用原型模式补单可以简化创建过程,而且也可以提升系统的整体性能。

 
注意事项

(1) 使用原型模式复制对象不会调用类的构造函数,对象是通过调用 Object 类的 clone() 方法来完成的,它直接在内存中复制数据。补单构造函数不会执行,甚至连访问权限都对原型模式无效。单例模式中,需要将构造函数的访问权限设置为 private,但是 clone() 方法直接无视构造方法的权限,所以单例模式与原型模式冲突,在使用时需要注意;

(2) 深拷贝与浅拷贝。Object 类的 clone() 方法只会拷贝对象中的基本数据类型(8种基本数据类型: byte, char, short, int, long, float, double, boolean 和 对应的封装类),对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组容器对象引用对象等另行拷贝。

  • 浅拷贝:只克隆对象中的基本数据类型,而不会克隆数组、容器、引用对象等。换言之,浅拷贝仅仅复制所拷贝的对象,而不复制它所引用的对象。如果变量为 String 字符串,则拷贝其引用地址,但是在修改的时候,它会从字符串常量池生成一个新的字符串,原有的字符串对象保持不变;
  • 深考本:把要拷贝的对象所引用的对象都克隆一遍。

 

参考文献

[1] https://blog.csdn.net/a745233700/article/details/83625951

以上是关于设计模式原型模式的主要内容,如果未能解决你的问题,请参考以下文章

原型模式

原型模式

5.原型模式

设计模式6:原型模式

设计模式原型模式

设计模式原型模式