大话设计模式读书笔记(七) 原型模式
原型模式(Prototype):
未使用设计模式代码:
1 package Prototype.NoPattern; 2 3 public class Resume { 4 private String name;//姓名 5 private int age; //年龄 6 private String sex; //性别 7 8 private String timeAree; //工作时长 9 private String company; //公司 10 11 public void setPersonInfo(int age,String sex){//设置个人信息 12 this.age = age; 13 this.sex = sex; 14 } 15 16 public void setWorkExperience(String timeAree,String company){//设置工作经历 17 this.timeAree = timeAree; 18 this.company = company; 19 } 20 21 public void display(){//显示 22 System.out.println(name+" "+age+" "+sex); 23 System.out.println("工作经历:"+company +";工作年限:"+timeAree); 24 } 25 public Resume(String name) { 26 super(); 27 this.name = name; 28 } 29 }
1 public class Main { 2 public static void main(String[] args) { 3 Resume a = new Resume("大鸟"); 4 a.setPersonInfo(25, "男"); 5 a.setWorkExperience("2008-2010", "xx公司"); 6 7 Resume b = new Resume("大鸟"); 8 b.setPersonInfo(25, "男"); 9 b.setWorkExperience("2008-2010", "xx公司"); 10 11 Resume c = new Resume("大鸟"); 12 c.setPersonInfo(25, "男"); 13 c.setWorkExperience("2008-2010", "xx公司"); 14 15 a.display(); 16 b.display(); 17 c.display(); 18 } 19 }
按照大鸟的话来说,这就相当于 在以前没有打印的年代,手写代码一样。 当需要三份简历的时候,就需要些三次,如果需要二十份,则需要实例化二十次。而且当有一个地方出现错误的时候,需要改20处。很显然这样是很不好的。于是引出了设计模式:原型模式。
原型模式(Prototype):
原型模式UML类图:
源代码:
1 public interface Prototype extends Cloneable{//抽象克隆对象 2 public Object clone(); 3 }
1 public class ConcretePrototype implements Prototype{//具体克隆对象 2 public Object clone(){//最简单的克隆方法,由于没有属性就不复制值了 3 Prototype prototype = new ConcretePrototype(); 4 return prototype; 5 } 6 }
1 public class Client { 2 private Prototype prototype;//持有需要使用的原型接口对象 3 4 public Client(Prototype prototype) {//构造方法,需要传入一个需要克隆的对象 5 super(); 6 this.prototype = prototype; 7 } 8 public Prototype operation(){ 9 ConcretePrototype concretePrototype =(ConcretePrototype) prototype.clone(); 10 return concretePrototype ; 11 } 12 }
Java中的克隆:
Java的所有类都是从java.lang.Object类继承而来的,而Object类提供protected Object clone()方法对对象进行复制,子类当然也可以把这个方法置换掉,提供满足自己需要的复制方法。对象的复制有一个基本问题,就是对象通常都有对其他的对象的引用。当使用Object类的clone()方法来复制一个对象时,此对象对其他对象的引用也同时会被复制一份
Java语言提供的Cloneable接口只起一个作用,就是在运行时期通知Java虚拟机可以安全地在这个类上使用clone()方法。通过调用这个clone()方法可以得到一个对象的复制。由于Object类本身并不实现Cloneable接口,因此如果所考虑的类没有实现Cloneable接口时,调用clone()方法会抛出CloneNotSupportedException异常。
克隆满足的条件:
clone()方法将对象复制了一份并返还给调用者。所谓“复制”的含义与clone()方法是怎么实现的。一般而言,clone()方法满足以下的描述:
1.在派生类中覆盖基类的clone()方法,并声明为public【Object类中的clone()方法为protected的】。
2.在派生类的clone()方法中,调用super.clone()。
3.在派生类中实现Cloneable接口。
克隆后的对象与原对象比较:
(1)对任何的对象x,都有:x.clone()!=x。换言之,克隆对象与原对象不是同一个对象。
(2)对任何的对象x,都有:x.clone().getClass() == x.getClass(),换言之,克隆对象与原对象的类型一样。
(3)如果对象x的equals()方法定义其恰当的话,那么x.clone().equals(x)应当成立的。
在JAVA语言的API中,凡是提供了clone()方法的类,都满足上面的这些条件。JAVA语言的设计师在设计自己的clone()方法时,也应当遵守着三个
条件。一般来说,上面的三个条件中的前两个是必需的,而第三个是可选的。
利用原型模式实现简历打印:
1 public class Resume implements Cloneable{ 2 private String name; 3 private int age; 4 private String sex; 5 6 private String timeAree; 7 private String company; 8 9 public void setPersonInfo(int age,String sex){ 10 this.age = age; 11 this.sex = sex; 12 } 13 14 public void setWorkExperience(String timeAree,String company){ 15 this.timeAree = timeAree; 16 this.company = company; 17 } 18 19 public void display(){ 20 System.out.println(name+" "+age+" "+sex); 21 System.out.println("工作经历:"+company +";工作年限:"+timeAree); 22 } 23 24 public Resume() { 25 super(); 26 } 27 28 public Resume(String name) { 29 super(); 30 this.name = name; 31 } 32 33 public Resume(String name, int age, String sex, String timeAree, String company) { 34 this.name = name; 35 this.age = age; 36 this.sex = sex; 37 this.timeAree = timeAree; 38 this.company = company; 39 } 40 public Object clone() throws CloneNotSupportedException{ 41 return super.clone(); 42 } 43 } 44 45 public class Client {//打印方法,通过该方法实现克隆简历,相当于打印功能 46 Resume resume ; 47 48 public Client(Resume resume) { 49 super(); 50 this.resume = resume; 51 } 52 53 public Resume getResume() throws CloneNotSupportedException{ 54 return (Resume)resume.clone(); 55 } 56 }
1 public class Main { 2 public static void main(String[] args) throws CloneNotSupportedException{ 3 Resume resume = new Resume("小菜"); 4 resume.setPersonInfo(18, "男"); 5 resume.setWorkExperience("2016-2017", "XX公司"); 6 Client c = new Client(resume); 7 8 Resume resume2=c.getResume(); 9 Resume resume3=c.getResume(); 10 resume.display(); 11 resume2.display(); 12 resume3.display(); 13 } 14 }
深克隆与潜克隆:
b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。
浅克隆示例:
1 public class Dept implements Cloneable{//部门 2 String id; 3 String name; 4 public Dept(String id, String name) { 5 this.id = id; 6 this.name = name; 7 } 8 9 public Dept clone() throws CloneNotSupportedException{ 10 return (Dept) super.clone(); 11 } 12 }
1 public class Emp implements Cloneable{ 2 String name ; 3 String id; 4 Dept dept; 5 public Emp(String name, String id, Dept dept) { 6 super(); 7 this.name = name; 8 this.id = id; 9 this.dept = dept; 10 } 11 public Emp clone() throws CloneNotSupportedException{ 12 return (Emp) super.clone(); 13 } 14 }
1 public class Main { 2 public static void main(String[] args) throws CloneNotSupportedException { 3 Dept d = new Dept("1", "技术部"); 4 Dept d2 = d.clone(); 5 System.out.println(d == d2); 6 7 Emp e = new Emp("小明", "1", d); 8 Emp e2 = e.clone(); 9 10 System.out.println(e==e2); 11 System.out.println(e.dept==e2.dept); 12 } 13 }
结果为:
false false true
public class Emp implements Cloneable{ String name ; String id; Dept dept; public Emp(String name, String id, Dept dept) { super(); this.name = name; this.id = id; this.dept = dept; } public Emp clone() throws CloneNotSupportedException{ Emp emp = (Emp) super.clone(); emp.dept=dept.clone(); return emp; } }
通过序列化实现深克隆:
1 public class Dept implements Serializable{ 2 private static final long serialVersionUID = 6798532648769041110L; 3 String id; 4 String name; 5 public Dept(String id, String name) { 6 this.id = id; 7 this.name = name; 8 } 9 }
1 public class Emp implements Serializable{ 2 String name ; 3 String id; 4 Dept dept; 5 public Emp(String name, String id, Dept dept) { 6 super(); 7 this.name = name; 8 this.id = id; 9 this.dept = dept; 10 } 11 public Object deepClone() throws Exception{ 12 //将该对象序列化成流,因为写在流里的是对象的一个拷贝, 13 //而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝 14 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 15 ObjectOutputStream oos = new ObjectOutputStream(bos); 16 oos.writeObject(this); 17 //将流序列化成对象 18 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 19 ObjectInputStream ois = new ObjectInputStream(bis); 20 return ois.readObject(); 21 } 22 }
1 public class Main { 2 public static void main(String[] args) throws Exception { 3 Dept d = new Dept("1", "技术部"); 4 5 Emp e = new Emp("小明", "1", d); 6 Emp e2 = (Emp) e.deepClone(); 7 8 System.out.println(e==e2); 9 System.out.println(e.dept==e2.dept); 10 } 11 }
此时,输出的结果一样是false,false.