• 原型设计模式


    一、原型模式

    1、定义

    原型模式(Prototype Pattern)指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象,属于创建型设计模式。

    原型模式的核心在于复制原型对象

    2、结构

    (1)模式的结构

    主要角色如下:

    • 客户类(Client):客户类提出创建对象的请求
    • 抽象原型(Iprototype):规定复制接口。
    • 具体原型(ConcretePrototype):被复制的对象。

    注意:不是通过直接 new关键字而是通过复制对象来实现创建对象的模式被称作原型模式。

    3、优缺点

    优点:

    • Java自带的原型模式基于内存二进制流的复制,在性能上比直接 new更好。
    • 通过深拷贝方式保存对象状态,简化创建对象的过程。

    缺点:

    • 需要为每一个类都配置一个 clone方法。
    • clone方法位于类的内部,如果对已有类进行改造时,需要修改代码,违背了开闭原则。
    • 当对象之间存在多重嵌套引用时,使用深拷贝会比较麻烦,每一层对象对应的类都必须支持深拷贝。

    4、使用场景

    • 创建对象成本较大,需要优化资源
    • 系统中大量使用该类对象,并且各个调用者都需要它的属性重复赋值。

    5、在框架源码中使用

    二、模式的通用实现

    代码如下:

    public class PrototypePattern {
    
    	public static void main(String[] args) {
    		ConcretePotrotypeA potrotypeA = new ConcretePotrotypeA();
    		potrotypeA.setDesc("ConcretePotrotypeA");
    
    		ConcretePotrotypeA clone = potrotypeA.clone();
    		clone.setDesc("clone");
    		System.out.println(potrotypeA);
    		System.out.println(clone);
    	}
    }
    
    /**
     * 抽象原型
     * 
     * @param 
     */
    interface IPrototype<T> {
    	// 复制
    	T clone();
    }
    
    /**
     * 具体原型
     */
    class ConcretePotrotypeA implements IPrototype<ConcretePotrotypeA> {
    
    	private String desc;
    
    	@Override
    	public ConcretePotrotypeA clone() {
    		// 进行复制
    		ConcretePotrotypeA concretePotrotypeA = new ConcretePotrotypeA();
    		concretePotrotypeA.setDesc(this.getDesc());
    		return concretePotrotypeA;
    	}
    
    	public String getDesc() {
    		return desc;
    	}
    
    	public void setDesc(String desc) {
    		this.desc = desc;
    	}
    
    	@Override
    	public String toString() {
    		return "ConcretePotrotypeA{" + "desc='" + desc + '\'' + '}';
    	}
    }
    
    • 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

    三、模式的应用实例

    1、浅拷贝

    Java内置了 Cloneable抽象原型接口,自定义的类只需要实现该接口并重写 Object.clone()方法即可完成本类的复制。

    在这里插入图片描述

    一般使用 clone方法,需要满足几个条件:

    • 对任何对象,都有 o.clone() != o。即克隆对象与原型对象不是同一个对象。
    • 对任何对象,都有 o.clone().getClass() = o.getClass()。即克隆对象与原型对象的类型一样。
    • 如果对象 o的 equals()方法定义恰当,则 o.clone().equals(o) 应当成立,可选条件。

    代码如下;

    public class ConcretePotrotypeB implements Cloneable{
    
        private String desc;
    
        private List<String> userList;
    
        /**
         * 浅拷贝
         * @return
         */
        @Override
        protected ConcretePotrotypeB clone(){
            ConcretePotrotypeB clone = null;
            try {
                /**
                 * super.clone()方法是基于内存二进制流的复制
                 */
                clone = (ConcretePotrotypeB) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return clone;
        }
        
    // get/set
    
    }
    
    • 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

    测试:

    	public static void main(String[] args) {
    		ConcretePotrotypeB potrotypeB = new ConcretePotrotypeB();
    		potrotypeB.setDesc("ConcretePotrotypeB");
    		List<String> userList = new ArrayList<>();
    		userList.add("赵云");
    		userList.add("后裔");
    		potrotypeB.setUserList(userList);
    
    		ConcretePotrotypeB clone = potrotypeB.clone();
    		clone.setDesc("clone");
    		clone.getUserList().add("安琪拉");
    
    		System.out.println(potrotypeB);
    		System.out.println(clone);
    		System.out.println(clone == potrotypeB);
    		System.out.println(clone.getClass() == potrotypeB.getClass());
    		System.out.println(clone.equals(potrotypeB));
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    注意:

    • 浅拷贝:如果类中存在引用对象属性,则原型对象与克隆对象的该属性会执行同一对象属性的引用。
    • super.clone()方法:是直接从堆内存中以二进制流的方式进行复制,重新分配一个内存块,因此其效率很高。

    2、深拷贝

    针对引用对象属性的深拷贝, 手动给克隆对象的该属性分配另一块内存即可。在 Java中,如果想要完成原型对象的深克隆,通常使用序列化(Serializable )的方式来完成。

    代码如下;

    public class ConcretePotrotypeC implements Cloneable, Serializable {
    
    	private String desc;
    
    	private List<String> userList;
    
    	/**
    	 * 浅拷贝
    	 * 
    	 * @return
    	 */
    	@Override
    	protected ConcretePotrotypeC clone() {
    		return deepClone();
    	}
    
    	/**
    	 * 深拷贝
    	 * 
    	 * @return
    	 */
    	public ConcretePotrotypeC deepClone() {
    		try {
    			ByteArrayOutputStream bos = new ByteArrayOutputStream();
    			ObjectOutputStream oos = new ObjectOutputStream(bos);
    			oos.writeObject(this);
    
    			ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
    			ObjectInputStream ois = new ObjectInputStream(bis);
    			return (ConcretePotrotypeC) ois.readObject();
    		} catch (Exception e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    
    // get/set
    }
    
    • 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

    测试:

    	public static void main(String[] args) {
    		ConcretePotrotypeC potrotypeC = new ConcretePotrotypeC();
    		potrotypeC.setDesc("ConcretePotrotypeC");
    		List<String> userList = new ArrayList<>();
    		userList.add("赵云");
    		userList.add("后裔");
    		potrotypeC.setUserList(userList);
    
    		ConcretePotrotypeC clone = potrotypeC.clone();
    		clone.setDesc("clone");
    		clone.getUserList().add("安琪拉");
    
    		System.out.println(potrotypeC);
    		System.out.println(clone);
    		System.out.println(clone == potrotypeC);
    		System.out.println(clone.getClass() == potrotypeC.getClass());
    		System.out.println(clone.equals(potrotypeC));
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    参考文章:

    – 求知若饥,虚心若愚。

  • 相关阅读:
    并查集的简单学习笔记
    贴片天线的特征模分析及其应用
    职场中的“显眼包”却是领导的心头宝!
    c++中的string类
    Linux下安装Mysql5.7,超详细完整教程,以及云mysql连接
    关于Unity自带的保存简单且持久化数据PlayerPrefs类的使用
    Easy Forms: Advanced Form Builder and Manager
    Python条件语句+字典
    如何扫码分享文件?二维码扫描预览文件的方法
    《发现的乐趣》作者费曼(读书笔记)
  • 原文地址:https://blog.csdn.net/qq_42402854/article/details/128105990