原型模式

一)故事
个性化电子账单

二)定义
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

三)代码例子
共计一个类:1)原型类;
1)原型类
/**
 *  原型类
 *
 * @author levovo
 */
public class PrototypeClass implements java.lang.Cloneable {
    private String title = null;// 完全拷贝(深拷贝)
    private String name = null;// 完全拷贝(深拷贝)
    private int number = 0; // 完全拷贝(深拷贝)
    // 数组与对象
    private ArrayList<String> list = new ArrayList(); // 引用拷贝(浅拷贝)
    private Version version = new Version();// 引用拷贝(浅拷贝)
    private Integer[] integerArray = new Integer[6];// 引用拷贝(浅拷贝)
    private int arrayIndex = 0;
    // static
    private static Version versionStatic = new Version(); // 引用拷贝(浅拷贝)(仅有一个实例)
    private static int numberStatic = 0;// 引用拷贝(浅拷贝)(仅有一个实例)
    // final
    private final Version versionFinal = new Version();
    private final int numberFinal = 999;
    // 覆盖父类Object方法
    @Override
    protected PrototypeClass clone() {
        PrototypeClass prototype = null;
        try {
            // 浅拷贝
            prototype = (PrototypeClass)super.clone();
            // 对象深拷贝
            prototype.list = (ArrayList<String>)this.list.clone();
            // 对象深拷贝
            prototype.version = (Version)this.version.clone();
            // 数组深拷贝
            prototype.integerArray = (Integer[])this.integerArray.clone();
        } catch (CloneNotSupportedException ex) {
            
        }
        return prototype;
    }
    
    public void setTitle(String _title) {
        this.title = _title;
        //        System.out.println("PrototypeClass()->setTitle():"+this.title);
    }
    
    public String getTitle() {
        return this.title;
    }
    
    /**
     * @return the number
     */
    public int getNumber() {
        return number;
    }
    
    /**
     * @param number the number to set
     */
    public void setNumber(int number) {
        this.number = number;
    }
    
    public void setList(String value) {
        this.getList().add(value);
    }
    
    public ArrayList<String> getList() {
        return this.list;
    }
    
    /**
     * @return the name
     */
    public String getName() {
        return name;
    }
    
    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
    
    /**
     * @param list the list to set
     */
    public void setList(ArrayList<String> list) {
        this.list = list;
    }
    
    /**
     * @return the version
     */
    public Version getVersion() {
        return version;
    }
    
    /**
     * @param version the version to set
     */
    public void setVersion(Version version) {
        this.version = version;
    }
    
    /**
     * @return the integerArray
     */
    public Integer[] getIntegerArray() {
        return integerArray;
    }
    
    /**
     * @param integerArray the integerArray to set
     */
    public void setIntegerArray(int integerArray) {
        this.integerArray[arrayIndex] = integerArray;
    }
    
    /**
     * @return the versionFinal
     */
    public Version getVersionFinal() {
        return versionFinal;
    }
    
    /**
     * @return the numberFinal
     */
    public int getNumberFinal() {
        return numberFinal;
    }
    
    /**
     * @return the versionStatic
     */
    public static Version getVersionStatic() {
        return versionStatic;
    }
    
    /**
     * @param aVersionStatic the versionStatic to set
     */
    public static void setVersionStatic(Version aVersionStatic) {
        versionStatic = aVersionStatic;
    }
    
    /**
     * @return the numberStatic
     */
    public static int getNumberStatic() {
        return numberStatic;
    }
    
    /**
     * @param aNumberStatic the numberStatic to set
     */
    public static void setNumberStatic(int aNumberStatic) {
        numberStatic = aNumberStatic;
    }
}

一个类
/**
 *  一个类
 * 
 * @author levovo
 */
public class Version implements java.lang.Cloneable {
    private String name = null;
    private int code = 0;
    
    // 覆盖父类Object方法
    @Override
    protected Version clone() {
        Version version = null;
        try {
            version = (Version)super.clone();
        } catch (CloneNotSupportedException ex) {
            
        }
        return version;
    }
    
    /**
     * @return the name
     */
    public String getName() {
        return name;
    }
    
    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
    
    /**
     * @return the code
     */
    public int getCode() {
        return code;
    }
    
    /**
     * @param code the code to set
     */
    public void setCode(int code) {
        this.code = code;
    }
    
}


场景使用例子

/**
 *  场景使用例子
 *
 * @author levovo
 */
public class Client {
    public static void main(String[] args) {
        // 旧的
        PrototypeClass prototypeOld = new PrototypeClass();
        prototypeOld.setTitle("titleOld");
        String name = new String("nameOld");
        prototypeOld.setName(name);
        prototypeOld.setNumber(10001);
        prototypeOld.setList("listOld");
        prototypeOld.getVersion().setName("version name....Old");
        prototypeOld.getVersion().setCode(20001);
        prototypeOld.setIntegerArray(100);
        prototypeOld.setNumberStatic(100);
        prototypeOld.getVersionStatic().setName("version name...static...Old");
        prototypeOld.getVersionStatic().setCode(30001);
        //        prototypeOld.set
        // clone的
        PrototypeClass prototypeClone = prototypeOld.clone();
        // 修改
        System.out.println("--- modify ---");
        prototypeOld.setTitle("titleChange");
        String name1 = new String("nameChange");
        prototypeOld.setName(name1);
        prototypeOld.setNumber(10002);
        prototypeOld.setList("listChange");
        prototypeOld.getVersion().setName("version name....Change");
        prototypeOld.getVersion().setCode(20002);
        prototypeOld.setIntegerArray(200);
        prototypeOld.setNumberStatic(200);
        prototypeOld.getVersionStatic().setName("version name...static...Change");
        prototypeOld.getVersionStatic().setCode(30002);
        System.out.println("--- 比较 ---");
        //        prototypeOld.getTitle().contains(name);
        if (prototypeOld.getTitle().equals(prototypeClone.getTitle())) {
            System.out.println("String title -> 属于引用拷贝(浅拷贝)");
        }else{
            System.out.println("String title -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getName().equals(prototypeClone.getName())) {
            System.out.println("String name -> 属于引用拷贝(浅拷贝)");
        }else{
            System.out.println("String name -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getNumber() == prototypeClone.getNumber()) {
            System.out.println("int number -> 属于引用拷贝(浅拷贝)");
        }else{
            System.out.println("int number -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getList().equals(prototypeClone.getList())) {
            System.out.println("ArrayList<String> list -> 属于引用拷贝(浅拷贝)");
        }else{
            System.out.println("ArrayList<String> list -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getVersion().equals(prototypeClone.getVersion())) {
            System.out.println("Version version -> 属于引用拷贝(浅拷贝)");
        }else{
            System.out.println("Version version -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getVersion().getName().equals(prototypeClone.getVersion().getName())) {
            System.out.println("Version version.getName() -> 属于引用拷贝(浅拷贝)");
        }else{
            System.out.println("Version version.getName() -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getVersion().getCode() == prototypeClone.getVersion().getCode()) {
            System.out.println("Version version.getCode() -> 属于引用拷贝(浅拷贝)");
        }else{
            System.out.println("Version version.getCode() -> 属于完全拷贝(深拷贝)");
        }
        
        System.out.println("prototypeOld.getIntegerArray()[0]:"+prototypeOld.getIntegerArray()[0]);
        System.out.println("prototypeClone.getIntegerArray()[0]:"+prototypeClone.getIntegerArray()[0]);
        if (prototypeOld.getIntegerArray()[0] == prototypeClone.getIntegerArray()[0]) {
            System.out.println("Integer[] integerArray -> 属于引用拷贝(浅拷贝)");
        }else{
            System.out.println("Integer[] integerArray -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getNumberStatic() == prototypeClone.getNumberStatic()) {
            System.out.println("static int numberStatic -> 属于引用拷贝(浅拷贝)(仅一个实例)");
        }else{
            System.out.println("static int numberStatic -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getVersionStatic().equals(prototypeClone.getVersionStatic())) {
            System.out.println("static Version versionStatic -> 属于引用拷贝(浅拷贝)(仅一个实例)");
        }else{
            System.out.println("static Version versionStatic -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getVersionStatic().getName().equals(prototypeClone.getVersionStatic().getName())) {
            System.out.println("static Version versionStatic.getName() -> 属于引用拷贝(浅拷贝)(仅一个实例)");
        }else{
            System.out.println("static Version versionStatic.getName() -> 属于完全拷贝(深拷贝)");
        }
        
        if (prototypeOld.getVersionStatic().getCode() == prototypeClone.getVersionStatic().getCode()) {
            System.out.println("static Version versionStatic.getCode() -> 属于引用拷贝(浅拷贝)(仅一个实例)");
        }else{
            System.out.println("static Version versionStatic.getCode() -> 属于完全拷贝(深拷贝)");
        }
        
        System.out.println("prototypeOld.getNumberFinal():"+prototypeOld.getNumberFinal());
        System.out.println("prototypeClone.getNumberFinal():"+prototypeClone.getNumberFinal());
        
        // 总论:
        // 1)内部的数组(如Object[]和ArrayList<String>)和对象是拷贝引用,不是拷贝对象
        // 2)基本类型是属于完全拷贝(深拷贝),String也算是基本类型
    }
}

打印结果:

--- modify ---
--- 比较 ---
String title -> 属于完全拷贝(深拷贝)
String name -> 属于完全拷贝(深拷贝)
int number -> 属于完全拷贝(深拷贝)
ArrayList<String> list -> 属于完全拷贝(深拷贝)
Version version -> 属于完全拷贝(深拷贝)
Version version.getName() -> 属于完全拷贝(深拷贝)
Version version.getCode() -> 属于完全拷贝(深拷贝)
prototypeOld.getIntegerArray()[0]:200
prototypeClone.getIntegerArray()[0]:100
Integer[] integerArray -> 属于完全拷贝(深拷贝)
static int numberStatic -> 属于引用拷贝(浅拷贝)(仅一个实例)
static Version versionStatic -> 属于引用拷贝(浅拷贝)(仅一个实例)
static Version versionStatic.getName() -> 属于引用拷贝(浅拷贝)(仅一个实例)
static Version versionStatic.getCode() -> 属于引用拷贝(浅拷贝)(仅一个实例)
prototypeOld.getNumberFinal():999
prototypeClone.getNumberFinal():999

四)优点
1)性能优良
原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
2)逃避构造函数的约束
这即是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。

五)缺点

六)使用场景
1)资源优化场景
类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
2)性能和安全要求的场景
通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
3)一个对象多个修改者的场景
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
原型模式已经与Java融为一体了,随时拿来用,java.lang.Cloneable

七)注意事项
1)构造函数不会被执行
2)浅拷贝和深拷贝
浅拷贝,即拷贝引用,指向原生对象的内部元素地址,共享一个私有变量。
深拷贝,即完全拷贝,两个对象这间没有任何的瓜葛,你修改你的,我修改我的,不相互影响。
注:深拷贝和浅拷贝建议不要混合使用,特别是在涉及类的继承时,父类有多个引用的情况就非常复杂,建议的方案是深拷贝和浅拷贝分开实现。
3)clone与final两个冤家
对象clone与对象内的final关键字是有冲突的,想要实现拷贝,则删除掉final关键字,这是最便捷、安全、快捷的方式。你要使用clone方法,在类的成员变量上就不要增加final关键字。
注:要使用clone方法,类的成员变量上就不要增加final关键字。

八)扩展

九)总结
理解浅拷贝和深拷贝,浅拷贝是引用,浅拷贝是完全拷贝。基本类型,如:int,long,double和String对象(String对象看作是基本类型)都是深拷贝,而数组(如:Integer[]、Double[])和对象(如:ArrayList<String>、Version())都是浅拷贝。想要实现数组和对象的深拷贝,则在clone()方法里加入深拷贝代码,如下:

// 实现java.lang.Cloneable接口中的方法clone()
public class PrototypeClass implements java.lang.Cloneable {
    // 数组与对象
    private ArrayList<String> list = new ArrayList(); // 引用拷贝(浅拷贝)
    private Version version = new Version();// 引用拷贝(浅拷贝)
    private Integer[] integerArray = new Integer[6];// 引用拷贝(浅拷贝)
    private int arrayIndex = 0;
    // 覆盖父类Object方法
    @Override
    protected PrototypeClass clone() {
        PrototypeClass prototype = null;
        try {
            // 浅拷贝
            prototype = (PrototypeClass)super.clone();
            // 对象深拷贝
            prototype.list = (ArrayList<String>)this.list.clone();
            // 对象深拷贝
            prototype.version = (Version)this.version.clone();
            // 数组深拷贝
            prototype.integerArray = (Integer[])this.integerArray.clone();
        } catch (CloneNotSupportedException ex) {
            
        }
        return prototype;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值