设计模式学习笔记(原型模式)
原型模式
用原型的实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
在Java中使用原型模式需要实现 java.lang.Cloneable 接口。对于有些构造函数要执行很长时间的对象,在不需要改变初始化信息的情况下使用克隆可以大大的提高性能。
public class Food {public String name;public Food(String name) {this.name = name;}}//实现 java.lang.Cloneable 接口public class Pet implements Cloneable {public String name;public int age;public List<Food> foods = new ArrayList<Food>();public Pet(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Pet clone() {Pet copy = null;try {copy = (Pet) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return copy;}}public class Test {public static void main(String[] args) {Pet source = new Pet("小狗", 2);source.foods.add(new Food("小狗爱吃狗粮"));Pet copy = source.clone();//修改前System.out.println("-----------值修改前-----------");System.out.println("source name: " + source.name);System.out.println(" source age: " + source.age);System.out.println("source food: " + source.foods.get(0).name);System.out.println(" copy name: " + copy.name);System.out.println(" copy age: " + copy.age);System.out.println(" copy food: " + copy.foods.get(0).name); System.out.println("-----------值修改后-----------");copy.name = "小狗变小猫";copy.age = 5;copy.foods.get(0).name = "小猫要吃猫粮";System.out.println("source name: " + source.name);System.out.println(" source age: " + source.age);System.out.println("source food: " + source.foods.get(0).name);System.out.println(" copy name: " + copy.name);System.out.println(" copy age: " + copy.age);System.out.println(" copy food: " + copy.foods.get(0).name);}}运行Test程序输出:-----------值修改前-----------source name: 小狗 source age: 2source food: 小狗爱吃狗粮 copy name: 小狗 copy age: 2 copy food: 小狗爱吃狗粮-----------值修改后-----------source name: 小狗 source age: 2source food: 小猫要吃猫粮 copy name: 小狗变小猫 copy age: 5 copy food: 小猫要吃猫粮
由此输出可见name与age字段都复制过来了,改变copy对象的值后source对象的值还是保持不变,但Pet对象中foods变量是一个List对象的引用,Object的clone方法是“浅复制”并没有复制变量引用的对象,因而copy对foods的修改就等于对source的修改。
要做到“深复制”在Java中有3种方式
1)所有对象都实现 java.lang.Cloneable 接口
2)利用Java的序列化和反序列化,要求所有对象都实现 java.io.Serializable 接口,如果有确实不可序列化的对象可使用 transient 关键字声明,从而将之排除在序列化之外
3)自己手动编码实现