GOF23设计模式之原型模式(prototype)

一、原型模式概述

  1.通过new产生一个对象需要非常繁琐的数据准备和访问权限,则可以使用原型模式。

  2.就是java中的克隆技术,以某个对象为原型,复制出新的对象,显然,新的对象具备原型对象的特点。

  3.优势:效率高(直接克隆,避免了重新执行构造函数的过程)。

  4.克隆类似于new,但是不同于new。
    new创建出来的对象属性采用默认值,克隆出来的对象属性值完全和原型对象相同,并且克隆出的新对象不会影响原型对象,然后,再修改克隆对象的值。

  是否使用原型模式比较:

    1.如果需要创建大量不费时的对象,new的对象和clone的对象效率相当

    2.如果需要创建大量耗时的对象,建议使用原型模式

二、原型模式三种实现方式

  1.浅复制:类中实现 Cloneable接口,重写clone方法

  2.深复制:类中实现 Cloneable接口,重写clone方法时将对象一起克隆

  3.深复制:类中实现 Serializable接口,利用反序列化实现深克隆

  浅复制,深复制知识请点击此处

三、使用浅复制实现原型模式

  1.使用原型模式克隆多利羊

 1 /**
 2  * 原型模式(浅克隆)
 3  * @author CL
 4  *
 5  */
 6 public class Sheep implements Cloneable {
 7     private String name;
 8     
 9     public Object clone() throws CloneNotSupportedException {
10         return super.clone();
11     }
12 
13     public Sheep() {
14     }
15 
16     public Sheep(String name) {
17         this.name = name;
18     }
19 
20     public String getName() {
21         return name;
22     }
23 
24     public void setName(String name) {
25         this.name = name;
26     }
27     
28 }

  2.测试

 1 public class TestSheep {
 2     
 3     public static void main(String[] args) throws Exception {
 4         Sheep s1 = new Sheep("多利");
 5         Sheep s2 = (Sheep) s1.clone();    //克隆对象
 6         
 7         System.out.println(s1.hashCode()+"(原型对象)-->"+s1.getName());
 8         System.out.println(s2.hashCode()+"(克隆对象)-->"+s2.getName());
 9         
10         s2.setName("少利");    //对克隆对象修改,不影响原对象的属性值
11         
12         System.out.println("\n--------修改克隆对象的属性值后---------\n");
13         
14 
15         System.out.println(s1.hashCode()+"(原型对象)-->"+s1.getName());
16         System.out.println(s2.hashCode()+"(克隆对象)-->"+s2.getName());
17     }
18 
19 }

  控制台输出:

366712642(原型对象)-->多利
1829164700(克隆对象)-->多利

--------修改克隆对象的属性值后---------

366712642(原型对象)-->多利
1829164700(克隆对象)-->少利

四、使用深复制实现原型模式(1)

  1.使用原型模式克隆多利羊

 1 import java.util.Date;
 2 
 3 /**
 4  * 原型模式(深克隆)
 5  * @author CL
 6  *
 7  */
 8 public class Sheep implements Cloneable {
 9     private String name;
10     
11     private Birthday birthday;
12     
13     public Object clone() throws CloneNotSupportedException {
14         Sheep s = (Sheep) super.clone();    //克隆对象
15         s.birthday = (Birthday) this.birthday.clone();
16         return s;
17     }
18 
19     public Sheep() {
20     }
21 
22     public Sheep(String name, Birthday birthday) {
23         this.name = name;
24         this.birthday = birthday;
25     }
26 
27     public String getName() {
28         return name;
29     }
30 
31     public void setName(String name) {
32         this.name = name;
33     }
34 
35     public Birthday getBirthday() {
36         return birthday;
37     }
38 
39     public void setBirthday(Birthday birthday) {
40         this.birthday = birthday;
41     }
42     
43     
44 }
45 
46 class Birthday implements Cloneable {
47     private Date birthday;
48     
49     protected Object clone() throws CloneNotSupportedException {
50         return super.clone();
51     }
52 
53     public Birthday() {
54     }
55 
56     public Birthday(Date birthday) {
57         this.birthday = birthday;
58     }
59 
60     public Date getBirthday() {
61         return birthday;
62     }
63 
64     public void setBirthday(Date birthday) {
65         this.birthday = birthday;
66     }
67 }

  2.测试

 1 import java.util.Date;
 2 
 3 /**
 4  * 测试原型模式(深克隆)
 5  * @author CL
 6  *
 7  */
 8 public class TestSheep {
 9     
10     public static void main(String[] args) throws Exception {
11         Birthday date = new Birthday(new Date(5456464L));
12         Sheep s1 = new Sheep("多利", date);
13         Sheep s2 = (Sheep) s1.clone();    //克隆对象
14         
15         System.out.println(s1.hashCode()+"(原型对象)-->"+s1.getName()+"-->"+s1.getBirthday().getBirthday());
16         System.out.println(s2.hashCode()+"(克隆对象)-->"+s2.getName()+"-->"+s2.getBirthday().getBirthday());
17         
18         date.setBirthday(new Date());    //对原对象修改,克隆对象的属性值不改变
19         
20         System.out.println("\n--------修改克隆对象的属性值后---------\n");
21 
22         System.out.println(s1.hashCode()+"(原型对象)-->"+s1.getName()+"-->"+s1.getBirthday().getBirthday());
23         System.out.println(s2.hashCode()+"(克隆对象)-->"+s2.getName()+"-->"+s2.getBirthday().getBirthday());
24     }
25 
26 }

  控制台输出:

366712642(原型对象)-->多利-->Thu Jan 01 09:30:56 CST 1970
1550089733(克隆对象)-->多利-->Thu Jan 01 09:30:56 CST 1970
366712642(原型对象)-->多利-->Fri Dec 29 17:03:26 CST 2017
1550089733(克隆对象)-->多利-->Thu Jan 01 09:30:56 CST 1970

五、使用深复制实现原型模式(2)

  1.使用原型模式克隆多利羊

 1 import java.io.Serializable;
 2 import java.util.Date;
 3 
 4 /**
 5  * 原型模式(利用反序列化实现深克隆)
 6  * @author CL
 7  *
 8  */
 9 public class Sheep implements Serializable {
10     private String name;
11     
12     private Birthday birthday;
13     
14     public Sheep() {
15     }
16 
17     public Sheep(String name, Birthday birthday) {
18         this.name = name;
19         this.birthday = birthday;
20     }
21 
22     public String getName() {
23         return name;
24     }
25 
26     public void setName(String name) {
27         this.name = name;
28     }
29 
30     public Birthday getBirthday() {
31         return birthday;
32     }
33 
34     public void setBirthday(Birthday birthday) {
35         this.birthday = birthday;
36     }
37     
38 }
39 
40 class Birthday implements Serializable {
41     private Date birthday;
42 
43     public Birthday() {
44     }
45 
46     public Birthday(Date birthday) {
47         this.birthday = birthday;
48     }
49 
50     public Date getBirthday() {
51         return birthday;
52     }
53 
54     public void setBirthday(Date birthday) {
55         this.birthday = birthday;
56     }
57 }

  2.测试

 1 import java.io.ByteArrayInputStream;
 2 import java.io.ByteArrayOutputStream;
 3 import java.io.ObjectInputStream;
 4 import java.io.ObjectOutputStream;
 5 import java.util.Date;
 6 
 7 /**
 8  * 测试原型模式(利用反序列化实现深克隆)
 9  * @author CL
10  *
11  */
12 public class TestSheep {
13     
14     public static void main(String[] args) throws Exception {
15         Birthday date = new Birthday(new Date(5456464L));
16         Sheep s1 = new Sheep("多利", date);
17         
18         //利用反序列化实现深克隆
19         //1. 序列化
20         ByteArrayOutputStream bos = new ByteArrayOutputStream();
21         ObjectOutputStream oos = new ObjectOutputStream(bos);
22         oos.writeObject(s1);
23         byte[] bytes = bos.toByteArray();
24         
25         //2. 反序列化
26         ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
27         ObjectInputStream ois = new ObjectInputStream(bis);
28         Sheep s2 = (Sheep) ois.readObject();
29         
30         System.out.println(s1.hashCode()+"(原型对象)-->"+s1.getName()+"-->"+s1.getBirthday().getBirthday());
31         System.out.println(s2.hashCode()+"(克隆对象)-->"+s2.getName()+"-->"+s2.getBirthday().getBirthday());
32         
33         date.setBirthday(new Date());    //对原对象修改,克隆对象的属性值不改变
34         
35         System.out.println("\n--------------------修改克隆对象的属性值后---------------------\n");
36 
37         System.out.println(s1.hashCode()+"(原型对象)-->"+s1.getName()+"-->"+s1.getBirthday().getBirthday());
38         System.out.println(s2.hashCode()+"(克隆对象)-->"+s2.getName()+"-->"+s2.getBirthday().getBirthday());
39     }
40 
41 }

  控制台输出:

1442407170(原型对象)-->多利-->Thu Jan 01 09:30:56 CST 1970
1173230247(克隆对象)-->多利-->Thu Jan 01 09:30:56 CST 1970

--------------------修改克隆对象的属性值后---------------------

1442407170(原型对象)-->多利-->Fri Dec 29 17:11:21 CST 2017
1173230247(克隆对象)-->多利-->Thu Jan 01 09:30:56 CST 1970

六、原型模式常见应用场景

  1.原型模式很少单独出现,一般是和工厂方法模式一起出现。通过clone的方法创建一个对象,然后由工厂方法提供给调用者;

  2.Spring中的bean的创建其实就是两种:单例模式和原型模式(+工厂模式);

  3.………………

//对原型对象的修改

posted @ 2017-12-29 17:16  C3Stones  阅读(392)  评论(2编辑  收藏  举报