原型模式

定义

在软件系统中有时候需要多次创建某一类型的对象,为了简化创建过程,可以只需要创建一个对象,然后再通过克隆的方式复制出多个相同的对象,这就是原型模式的设计思想。

因为是使用克隆获取多个对象,因此原型模式可以分为两种形式:浅克隆、深克隆。

  • 浅克隆:对于基本数据类型,会进行数据的复制。而对于引用类型,只会复制其地址。因此,如果A是B浅克隆的结果,那么当我们修改A或B其中一方基本数据类型的值,另一方不会受到影响;但是如果我们修改其中一方的引用类型数据,另一方也会跟着一起改变,因为变量存储的只是一个地址值,它们指向相同的数据空间。
  • 深克隆:对于基本数据类型,进行数据的复制。而对于引用类型,会重新开辟一个空间,再将引用类型的数据进行复制,引用类型变量指向的是一个新的地址。因此,如果A是B深克隆的结果,那么无论修改A或B其中一方的变量,另一方都不会受到影响。

浅克隆

浅克隆的实现方式:

  1. 实现Cloneable接口
  2. 重写clone()方法
  3. 调用super.clone()

代码如下:

public class Class implements Cloneable {

	int number;
	ArrayList<String> students;

	@Override
	protected Object clone(){
		Object object=null;
		try {
			object=super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return object;
	}
}

测试代码:

	public static void main(String[] args) {
		Class A=new Class();
		A.setNumber(50);
		ArrayList<String> listA=new ArrayList<>();
		listA.add("A");
		A.setStudents(listA);
		Class B=(Class)A.clone();
		System.out.println("A:"+A);
		System.out.println("B:"+B);
		System.out.println("change");
		B.setNumber(44);
		ArrayList<String> listB = B.getStudents();
		listB.set(0,"B");
		System.out.println("A:"+A);
		System.out.println("B:"+B);
	}

输出结果:修改基本数据类型的数据,另一方不会跟着改变。修改引用类型数据,同时改变。
在这里插入图片描述

深克隆

深克隆有两个实现方法:

  1. 利用序列化:先将对象序列化转换成字节序列,再反序列化将字节序列恢复为对象。
  2. 利用引用类型自身实现的clone()方法。

深克隆方式一:序列化方法

  1. 实现序列化接口Serializable
  2. 序列化:将对象写入流中
  3. 反序列化:将对象从流中取出

代码如下:

public class Class implements Serializable {

	int number;
	ArrayList<String> students;
	
	Object deepClone1() throws IOException, ClassNotFoundException {
		ByteArrayOutputStream bao=new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bao);
		oos.writeObject(this);		//写入流
		ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bis);
		return (ois.readObject());	//从流读出
	}
}

测试:由于在流操作时将异常抛出了,所以在调用时要处理异常。

	public static void main(String[] args) {
		Class A=new Class();
		A.setNumber(50);
		ArrayList<String> listA=new ArrayList<>();
		listA.add("A");
		A.setStudents(listA);
		//Class B=(Class)A.clone();
		Class B= null;
		try {
			B = (Class)A.deepClone1();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println("A:"+A);
		System.out.println("B:"+B);
		System.out.println("change");
		B.setNumber(44);
		ArrayList<String> listB = B.getStudents();
		listB.set(0,"B");
		System.out.println("A:"+A);
		System.out.println("B:"+B);
	}

输出结果:修改一方的基本类型和引用类型,另一方都不会改变。
在这里插入图片描述
深克隆方式二:利用引用类型自身的Clone()方法

  1. 实现Cloneable接口
  2. super.clone()克隆整个对象。
  3. 对于引用类型,调用其自身的clone()方法。

代码如下:

public class Class implements Cloneable,Serializable {

	int number;
	ArrayList<String> students;
	
	Class deepClone2(){
		Class a=null;
		try {
			a=(Class)super.clone();
			a.students=(ArrayList)this.students.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return a;
	}
}

为什么这样使用就可以实现深克隆呢?我们可以查看一下ArrayList中clone()的源码,如下:

    public Object clone() {
        try {
            ArrayList var1 = (ArrayList)super.clone();
            //Arrays.copyOf方法会重新开辟一个this.size的空间,然后将this.elementData的数据复制到新的空间
            var1.elementData = Arrays.copyOf(this.elementData, this.size);	
            var1.modCount = 0;
            return var1;	//返回的var1是新的地址,而不是原先的地址值
        } catch (CloneNotSupportedException var2) {
            throw new InternalError(var2);
        }
    }

测试代码:

	public static void main(String[] args) {
		Class A=new Class();
		A.setNumber(50);
		ArrayList<String> listA=new ArrayList<>();
		listA.add("A");
		A.setStudents(listA);
		Class B=A.deepClone2();
		System.out.println("A:"+A);
		System.out.println("B:"+B);
		System.out.println("change");
		B.setNumber(44);
		ArrayList<String> listB = B.getStudents();
		listB.set(0,"B");
		System.out.println("A:"+A);
		System.out.println("B:"+B);
}

输出结果:修改一方的基本类型和引用类型,另一方都不会改变。
在这里插入图片描述

结论

使用原型模式,可以利用已有的实例简化对象的创建过程;如果需要保存变化不大的对象的状态,可以用深克隆方式进行备份。但需要为每一类配备一个克隆方法,如果是已存在的类,则会违背开闭原则。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值