• 设计模式之禅之设计模式-原型模式


    一:原型模式的定义
            --->用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
            --->原型模式(Prototype Pattern)的简单程度仅次于单例模式和迭代器模式。正是由于简单,使用的场景才非常地多
            --->原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的,为什么说是“标示”呢?翻开JDK的帮助看看Cloneable是一个方法都没有的,这个接口只是一个标记作用,在JVM中具有这个标记的对象才有可能被拷贝。那怎么才能从“有可能被拷贝”转换为“可以被拷贝”呢?方法是覆盖clone()方法,是的,你没有看错是重写clone()方法,看看我们上面Mail类中的clone方法.该方法重写了Object对象的方法

    二:原型模式的优点

            ● 性能优良
                   ---> 原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。

            ● 逃避构造函数的约束
                   --->这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的(参见13.4节)。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。


    三:原型模式的应用场景

            ● 资源优化场景
                    --->类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
            ● 性能和安全要求的场景
                    --->通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
            ● 一个对象多个修改者的场景
                    --->一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
                    --->在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与Java融为一体,大家可以随手拿来使用。


    四:原型模式的注意事项
            ---> 构造函数不会被执行
            --->注意浅拷贝。你可能会比较奇怪,为什么在Mail那个类中就可以使用String类型,而不会产生由浅拷贝带来的问题呢?内部的数组和引用对象才不拷贝,其他的原始类型比如int、long、char等都会被拷贝,但是对于String类型,Java就希望你把它认为是基本类型,它是没有clone方法的,处理机制也比较特殊,通过字符串池(stringpool)在需要的时候才在内存中创建新的字符串,读者在使用的时候就把String当做基本类使用即可。
            --->使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象。
            --->深拷贝还有一种实现方式就是通过自己写二进制流来操作对象,然后实现对象的深拷贝,这个大家有时间自己实现一下
            --->深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。

    五:clone和fianl两个冤家
            --->你要实现深拷贝的梦想在final关键字的威胁下破灭了,路总是有的,我们来想想怎么修改这个方法:删除掉final关键字,这是最便捷、安全、快速的方式
            --->你要使用clone方法,在类的成员变量上就不要增加final关键字。

    六:原型模式最佳实践

            --->可以这样理解:一个对象的产生可以不由零起步,直接从一个已经具备一定雏形的对象克隆,然后再修改为生产需要的对象。也就是说,产生一个人,可以不从1岁长到2岁,再到3岁......也可以直接找一个人,从其身上获得DNA,然后克隆一个,直接修改一下就是30岁了!我们讲的原型模式也就是这样的功能



    七:原型模式例子

    【1】原型模式的模板

     1 package com.yeepay.sxf.template8;
     2 /**
     3  * 邮件
     4  * @author sxf
     5  * 
     6  * 原型模式:(1)实现Cloneable接口
     7  *                    (2)重写Object的clone方法
     8  */
     9 public class Mail implements Cloneable{
    10     
    11     private String name;
    12     
    13     private String context;
    14     
    15     private String title;
    16     
    17     private String address;
    18 
    19     
    20     public Mail(String name, String context, String title, String address) {
    21         super();
    22         this.name = name;
    23         this.context = context;
    24         this.title = title;
    25         this.address = address;
    26     }
    27 
    28     
    29     /**
    30      * 克隆方法
    31      */
    32     @Override
    33     protected Mail clone() throws CloneNotSupportedException {
    34         Mail mail1=null;
    35         mail1=(Mail) super.clone();
    36         return mail1;
    37     }
    38 
    39 
    40     public String getName() {
    41         return name;
    42     }
    43 
    44     public void setName(String name) {
    45         this.name = name;
    46     }
    47 
    48     public String getContext() {
    49         return context;
    50     }
    51 
    52     public void setContext(String context) {
    53         this.context = context;
    54     }
    55 
    56     public String getTitle() {
    57         return title;
    58     }
    59 
    60     public void setTitle(String title) {
    61         this.title = title;
    62     }
    63 
    64     public String getAddress() {
    65         return address;
    66     }
    67 
    68     public void setAddress(String address) {
    69         this.address = address;
    70     }
    71     
    72     
    73 }
    View Code

    【2】浅拷贝

     1 package com.yeepay.sxf.template8;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 
     7 
     8 /**
     9  * 浅拷贝
    10  * @author sxf
    11  * (1)JVM做了一个偷懒的拷贝动作,Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象
    12 的内部元素地址,这种拷贝就叫做浅拷贝
    13  *(2)非常不安全
    14  *
    15  */
    16 public class Thing implements Cloneable {
    17     
    18     private List<String> list=new ArrayList<String>();
    19 
    20 
    21     @Override
    22     protected Thing clone() throws CloneNotSupportedException {
    23         Thing thing=null;
    24         thing=(Thing) super.clone();
    25         return thing;
    26     }
    27 
    28     public List<String> getList() {
    29         return list;
    30     }
    31 
    32     public void setList(String a) {
    33         this.list.add(a);
    34     }
    35     
    36     
    37 }
    View Code

    【3】深拷贝

     1 package com.yeepay.sxf.template8;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 /**
     6  * 深层次拷贝
     7  * (1)深拷贝还有一种实现方式就是通过自己写二进制流来操作对象,然后实现对象的深拷贝,这个大家有时间自己实现一下
     8  * (2)深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。
     9  * @author sxf
    10  *
    11  */
    12 public class Thing2 implements     Cloneable {
    13     private ArrayList<String> list=new ArrayList<String>();
    14 
    15 
    16     @Override
    17     protected Thing2 clone() throws CloneNotSupportedException {
    18         Thing2 thing2=null;
    19         thing2=(Thing2) super.clone();
    20         thing2.list=(ArrayList<String>) this.list.clone();
    21         return thing2;
    22     }
    23 
    24     public List<String> getList() {
    25         return list;
    26     }
    27 
    28     public void setList(String a) {
    29         this.list.add(a);
    30     }
    31     
    32 }
    View Code

    【4】客户端测试

     1 package com.yeepay.sxf.template8;
     2 
     3 import java.util.List;
     4 
     5 
     6 public class ClientTest {
     7 
     8     public static void main(String[] args) throws CloneNotSupportedException {
     9         //test01();
    10         //test02();
    11         test03();
    12     }
    13     
    14     /**
    15      * 原型模式:模板测试
    16      * @throws CloneNotSupportedException 
    17      */
    18     public static void test01() throws CloneNotSupportedException{
    19         Mail mail=new Mail("sxf", "go smx", "emailtosxf", "sxf@163.com");//ClientTest.main()com.yeepay.sxf.template8.Mail@2a5330
    20         System.out.println("ClientTest.main()"+mail.toString());
    21         Mail mail2=mail.clone();
    22         System.out.println("ClientTest.main()"+mail2.toString());//ClientTest.main()com.yeepay.sxf.template8.Mail@18872380
    23         
    24     }
    25     /**
    26      * 原型模式:浅拷贝
    27      * @throws CloneNotSupportedException 
    28      */
    29     public static void test02() throws CloneNotSupportedException{
    30         Thing thing1=new Thing();
    31         thing1.setList("小李");
    32         Thing thing2=thing1.clone();
    33         thing1.setList("小张");
    34         List<String> t=thing1.getList();
    35         List<String> t2=thing2.getList();
    36         for (int i = 0; i < t.size(); i++) {
    37             System.out.println("ClientTest.test02(t==>)"+t.get(i));
    38         }
    39         for (int i = 0; i < t2.size(); i++) {
    40             System.out.println("ClientTest.test02(t2==>)"+t2.get(i));
    41         }
    42         //ClientTest.test02(t==>)小李
    43         //ClientTest.test02(t==>)小张
    44         //ClientTest.test02(t2==>)小李
    45         //ClientTest.test02(t2==>)小张
    46     }
    47     
    48     /**
    49      * 原型模式:深拷贝
    50      * @throws CloneNotSupportedException 
    51      */
    52     public static void test03() throws CloneNotSupportedException{
    53         Thing2 thing2a=new Thing2();
    54         thing2a.setList("小李");
    55         Thing2 thing2b=thing2a.clone();
    56         thing2a.setList("小张");
    57         List<String> t=thing2a.getList();
    58         List<String> t2=thing2b.getList();
    59         for (int i = 0; i < t.size(); i++) {
    60             System.out.println("ClientTest.test02(t==>)"+t.get(i));
    61         }
    62         for (int i = 0; i < t2.size(); i++) {
    63             System.out.println("ClientTest.test02(t2==>)"+t2.get(i));
    64         }
    65         //ClientTest.test02(t==>)小李
    66         //ClientTest.test02(t==>)小张
    67         //ClientTest.test02(t2==>)小李
    68     }
    69 }
    View Code
  • 相关阅读:
    Linux系统调用
    Linux的中断 & 中断和异常的区别
    system v和posix的共享内存对比 & 共享内存位置
    epoll里面mmap释疑
    提高网络效率的总结
    推荐相关学习 & 典型算法、典型特征、典型推荐系统框架
    最大似然法理解
    调试多线程 & 查死锁的bug & gcore命令 & gdb对多线程的调试 & gcore & pstack & 调试常用命令
    内存屏障 & Memory barrier
    锁相关知识 & mutex怎么实现的 & spinlock怎么用的 & 怎样避免死锁 & 内核同步机制 & 读写锁
  • 原文地址:https://www.cnblogs.com/shangxiaofei/p/5125518.html
Copyright © 2020-2023  润新知