【设计模式】Prototype 原型模式

概述:
原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据。

应用场景:

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

复制原型分为浅克隆与深克隆:
浅克隆:当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。因此两个对象的interest公共同一个内存地址,一个对象变化,会引起另一个对象响应的变化。

深克隆:除了对象本身被复制外,对象所包含的所有成员变量也将被复制。

下边用测试代码来具体阐述两者的区别
角色分配:
Client:客户端
Prototype:原型模式中的核心,用于创建原型对象,其实现了Cloneable接口,重写了clone方法,并将访问权限改为public
ConcretePrototype:具体的需要创建的对象的类

测试代码:

/**
 * @Description 原型模式:实现Cloneable接口,重写Object的clone方法
 * @date 2019/10/21 16:33
 * @Version V1.0
 */
@Data
public class Prototype implements Cloneable {
    private String name;
    private String context;
    private String title;
    private String address;


    public Prototype(String name, String context, String title, String address) {
        this.name = name;
        this.context = context;
        this.title = title;
        this.address = address;
    }

    /**
     * 克隆方法
     */
    @Override
    protected Prototype clone() throws CloneNotSupportedException{
        return (Prototype) super.clone();
    }
  }

浅克隆:

/**
 * @ClassName Thing
 * @Description 浅拷贝 (1)JVM做了一个偷懒的拷贝动作,Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝
 * (2)非常不安全
 * @date 2019/10/21 16:45
 * @Version V1.0
 */
@Data
public class Thing implements Cloneable {
    private List<String> list = new ArrayList<String>();
    
    @Override
    protected Thing clone() throws CloneNotSupportedException{
        return (Thing) super.clone();
    }
  }

深克隆:

/**
 * @ClassName Thing2
 * @Description 深拷贝:除了对象本身被复制外,对象所包含的所有成员变量也将被复制
 * @date 2019/10/21 16:50
 * @Version V1.0
 */
@Data
public class Thing2 implements Cloneable {
    private ArrayList<String> list=new ArrayList<String>();

    @Override
    protected Thing2 clone() throws CloneNotSupportedException {
        Thing2 thing2=null;
        thing2=(Thing2) super.clone();
        thing2.list=(ArrayList<String>) this.list.clone();
        return thing2;
    }
  }

测试:

/**
 * @ClassName ClientTest
 * @Description TODO
 * @date 2019/10/21 16:52
 * @Version V1.0
 */
public class ClientTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        test01();
        test02();
        test03();
    }

    /**
     * 原型模式:模板测试
     */
    public static void test01() throws CloneNotSupportedException{
        Prototype mail=new Prototype("sxf", "go smx", "emailtosxf", "[email protected]");//ClientTest.main()com.yeepay.sxf.template8.Mail@2a5330
        System.out.println("ClientTest.main()"+mail.toString());
        Prototype mail2=mail.clone();
        System.out.println("ClientTest.main()"+mail2.toString());//ClientTest.main()com.yeepay.sxf.template8.Mail@18872380
    }
    /**
     * 原型模式:浅拷贝
     */
    public static void test02() throws CloneNotSupportedException{
        Thing thing1=new Thing();
        thing1.setList("小李");
        Thing thing2=thing1.clone();
        thing1.setList("小张");
        List<String> t=thing1.getList();
        List<String> t2=thing2.getList();
        System.out.println("-------------浅克隆开始--------------");
        for (int i = 0; i < t.size(); i++) {
            System.out.println("ClientTest.test02(t==>)"+t.get(i));
        }
        for (int i = 0; i < t2.size(); i++) {
            System.out.println("ClientTest.test02(t2==>)"+t2.get(i));
        }
        System.out.println("-------------浅克隆结束--------------");
    }


    /**
     * 原型模式:深拷贝
     */
    public static void test03() throws CloneNotSupportedException{
        Thing2 thing2a=new Thing2();
        thing2a.setList("小李");
        Thing2 thing2b=thing2a.clone();
        thing2a.setList("小张");
        List<String> t=thing2a.getList();
        List<String> t2=thing2b.getList();
        System.out.println("-------------深克隆开始--------------");
        for (int i = 0; i < t.size(); i++) {
            System.out.println("ClientTest.test02(t==>)"+t.get(i));
        }
        for (int i = 0; i < t2.size(); i++) {
            System.out.println("ClientTest.test02(t2==>)"+t2.get(i));
        }
        System.out.println("-------------深克隆结束--------------");
    }
}

测试结果:
在这里插入图片描述
原型设计模式中浅拷贝是将数组和引用对象的指针clone过来了,而深拷贝是将引用对象内部重新分配了内存地址,指针发生了变化。
要使用clone方法,在类的成员变量上就不要增加final关键字。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章