设计模式-2种 原型模式/Prototype Pattern(拷贝模式)

设计模式-原型模式

参考资料:尚硅谷设计模式.
萌新码农 摘自网络资源 + 自己的思考 若有错误请大佬们指点
参考资料网上重复篇章多 忘了参考了哪几位博主的文章 若有侵权 请私信 看到会加上链接

需求

克隆羊例子:现在有一只羊tom,姓名为:tom,年龄为:1,颜色为:白色,请编写程序创建和tom羊 属性完全相同的10只羊。

传统方式

public class CloneSheep {
	public static void main(String[] args) {
		Sheep sheep = new Sheep("tom","1","white");
		Sheep[] sheeps = new Sheep[10]; 
		for(int i=0;i<10;i++) {
			sheeps[i] = new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor()); 
		}
	}
}

优缺点说明

  1. 优点是比较好理解,简单易操作
  2. 在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低。
  3. 总是需要重新初始化对象,而不是动态地活得对象运行时地状态,不够灵活。
  4. 对象属性内新增基本类型或引用类型,代码修改交复杂

浅拷贝模式

// 第一步 :实现 Cloneable 接口
public class Sheep implements Cloneable {
	/**
		一顿属性 + set get
	*/
	
	// 第二步:重写 clone() 方法
	@Override
	protected Objet clone() throws CloneNotSupportedException {
		// 第三步:调用 super.clone() 方法
		return super.clone();
	}
}

说明

如需要克隆的类属性为基本数据类型 byte、short、int、long、char、float、double、boolean(8种) 或 String 类型(值传递)类型。直接使用浅拷贝即可完成需求。

若需要克隆的类属性有引用类型,则需要使用深拷贝。

public class CloneSheep {
	public static void main(String[] args) {
		Sheep sheep1 = new Sheep("tom",1,"white");
		Sheep sheep2 = (Sheep)sheep1.clone();
        // 1735600054---1735600054 若修改sheep1的地址 
        // sheep2 地址也会随之改变
        System.out.println(sheep1.getAddress().hashCode()+"---"+sheep2.getAddress().hashCode());
	}
}

深拷贝模式

方式一:在重写的 clone() 中直接 clone 引用模式(不推荐)

	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object deep = null;
		//这里完成对基本数据类型(属性)和 String 的克隆
		deep = super.clone();
		//对引用类型的属性,进行单独处理
		主类型 obj = (主类型)deep;
		obj.主类型内部引用类型对象 = (主类型内部引用类型)主类型内部引用类型对象.clone();
		return obj;
	}

说明

确实可以让主类型进行深克隆,但主类型内部引用类型过多会导致 clone() 代码繁琐,并且引用类型类内部也必须重写 clone() 方法 ,修改较为复杂。

方式二:通过对象的序列化实现(推荐)

	public Object deepClone() {
		
		// 创建流对象
		ByteArrayOutputStream bos = null; // 字节输出流
		ObjectOutputStream oos = null; // 对象输出流
		
		ByteArrayInputStream bis = null; // 字节输入流
		ObjectInputStream ois = null; // 对象输入流
		
		try{
			// 序列化 
			bos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(bos);
			oos.writeObject(this); //将自己作为对象流输出

			//反序列化
			bis = new ByteArrayInputStream(bos.toByteArray());
			ois = new ObjectInputStream(bis);
			主类型 copyObj = (主类型)ois.readObject();
			
			return copyObj;			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				bos.close();
				oos.close();
				bis.close();
				ois.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

说明

主类型及引用类型都需加上implements Serializable,否则可能会发生空指针异常。总体来说修改代码比第一种方式简便许多。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值