设计模式随笔(五):原型模式
概述
原型模式即为有一个样例模板,用户可以从这个模板中克隆出一个一样的对象。
使用场景
1.创建对象时,不仅继承父类结构,还包括继承原型对象的数据;
2.对目标对象的修改,不影响原型对象;
3.隐藏clone操作;
UML图
client:客户端角色
Prototype:抽象原型角色,抽象类/接口,来声明clone方法
ConcretePrototype:具体的原型类,客户端角色的使用对象,即被复制的对象
浅克隆
ConcretePrototype
@Data public class Sheep implements Cloneable, Serializable { private String name; private Date birthDay; @Override protected Object clone() throws CloneNotSupportedException { Object obj = super.clone(); Sheep sheep = (Sheep) obj; // 克隆时间 sheep.birthDay = (Date) this.birthDay.clone(); return sheep; } }
测试用例
public class TestClone { public static void main(String[] args) throws CloneNotSupportedException { Date date = new Date(); Sheep sheep = new Sheep(); sheep.setBirthDay(date); sheep.setName("多利"); Sheep cloneSheep = (Sheep) sheep.clone(); System.out.println(cloneSheep.getBirthDay()); System.out.println(cloneSheep.getName()); } }
深克隆
深克隆主要是把clone()方法中,改为
public Object deepClone() throws IOException, ClassNotFoundException{ //将对象写到流里 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); //从流里读回来 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); }
这样做的前提就是对象以及对象内部所有引用到的对象都是可序列化的,否则,就需要仔细考察那些不可序列化的对象可否设成transient,从而将之排除在复制过程之外。
浅度克隆显然比深度克隆更容易实现,因为Java语言的所有类都会继承一个clone()方法,而这个clone()方法所做的正式浅度克隆。
有一些对象,比如线程(Thread)对象或Socket对象,是不能简单复制或共享的。不管是使用浅度克隆还是深度克隆,只要涉及这样的间接对象,就必须把间接对象设成transient而不予复制;或者由程序自行创建出相当的同种对象,权且当做复制件使用。