大话设计模式读书笔记(七) 原型模式

原型模式(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 }

深克隆与潜克隆:

A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 
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

因为浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 所以复制员工时,员工所引用的部门还是原来员工的部门。
如果要深复制,则只需要将员工中的clone方法修改成如下:
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.


原文地址:https://www.cnblogs.com/xsyfl/p/6842515.html