原型模式(Prototype Pattern)简介

定义

原型模式(Prototype Pattern)是指原型实例指定创建对象的 种类,并且通过拷贝这些原型创建新的对象。调用者不需要知道任何创建细节,不调用构造函数。属于创建型模式。

使用场景

1、类初始化消耗资源较多;
2、new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等);
3、构造函数比较复杂。
4、循环体中生产大量对象时,可读性下降。
原型模式的应用也是比较广泛的,比如spring中的scope=“prototype”、JSON.parseObject()以及BeanUtils等。

原型模式的实现方法

1.通过简单工厂模式将getter、setter封装到某个方法中,代码如下:

public interface Prototype{ Prototype clone(); } 
import java.util.List;


public class ConcretePrototype implements Prototype { 
	private int age; 
	private String name; 
	private List hobbies;
	public int getAge() { 
		return age;
	} 
	public void setAge(int age) { 
		this.age = age; 
	} 
	public String getName() { 
		return name; 
	}
	public void setName(String name) { 
		this.name = name; 
	} 	
	public List getHobbies() { 
		return hobbies; 
	} 
	public void setHobbies(List hobbies) { 
		this.hobbies = hobbies; 
	}
	@Override 
	public ConcretePrototype clone() { 
		ConcretePrototype concretePrototype = new ConcretePrototype(); 
		concretePrototype.setAge(this.age);
		concretePrototype.setName(this.name);
	    concretePrototype.setHobbies(this.hobbies); 
	    return concretePrototype; 
	}

2.通过实现JDK提供的Cloneable接口,实现快速复制 :

public class ConcretePrototype implements  Cloneable { 
	@Override 
	protected Object clone() throws CloneNotSupportedException {
	 	//复制的业务逻辑
	 	return null; 
	}
}

原型模式的优缺点

优点:性能优良,Java自带的原型模式是基于内存二进制流的拷贝,比直接new一个对象性能上提升了许多;可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
缺点:必须配备克隆(或者可拷贝)方法;对克隆复杂对象或对克隆出的对象进行复杂改造时,易带来风险;深拷贝、浅拷贝要运用得当

浅克隆与深克隆(拓展)

浅克隆是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象;深克隆不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。简而言之,对象A1中包含对B1的引用,B1中包含对C1的引用。如果通过浅拷贝A1得到A2,那么A2 中依然包含对B1的引用,B1中依然包含对C1的引用;而深拷贝A1得到A2,那么A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用。
例如:

import java.util.ArrayList; 
import java.util.List; 

public class PrototypeTest { 
	public static void main(String[] args) { 
		ConcretePrototype prototype= new ConcretePrototype();
		prototype.setAge(18); 
		prototype.setName("prototype");
		List hobbies = new ArrayList<String>(); 
		hobbies.add("书法");
        hobbies.add("美术");
		prototype.setHobbies(hobbies); 
		ConcretePrototype cloneType= concretePrototype .clone(concretePrototype); 
		cloneType.getHobbies().add("技术控");
        System.out.println("原型对象:" + prototype);
        System.out.println("克隆对象:" + cloneType);
        System.out.println(prototype == cloneType);
        System.out.println("原型对象的爱好:" + prototype.getHobbies());
        System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
        System.out.println(prototype.getHobbies() == cloneType.getHobbies());
	} 
} 

运行结果:
在这里插入图片描述
我们给复制后的克隆对象新增一项爱好,发现原型对象也发生了变化,这显然不符合我们的预期。因为我们希望克隆出来的对象应该和原型对象是两个独立的对象,不应该再有联系了。从测试结果看出hobbies的引用地址是相同的,意味着只是完整复制了值类型数据,没有复制引用对象。换言之,所有的引用对象仍然指向原来的对象。这样的话,如果我们修改任意一个对象中的属性值,prototype和cloneType的hobbies值都会改变。这就是我们常说的浅克隆。
那么,如何实现深克隆呢,我们可以通过IO流的方式来实现:

public Object 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);
		ConcretePrototype copy =(ConcretePrototype)ois.readObject(); 
		return copy;
	}catch (Exception e){ 
		e.printStackTrace(); 
		return null; 
	}
}

此外,也可以通过JSON串的方式实现深克隆:

public ConcretePrototype deepClone(){
        JSONObject jsonObject = JSONObject.fromObject(this);
        Object o = JSONObject.toBean(jsonObject, ConcretePrototype.class);
        return (ConcretePrototype)o;
    }

利用上面的测试代码,调用deepClone方法,结果如下:
在这里插入图片描述
我们便得到了预期的结果!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值