手记

java设计模式-原型模式

原型模式
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
其实就是从一个对象在创建一个另外一个可定制的对象,并且不需要知道任何创建的细节。

原型类:

package com.hy.prototype;

public class Prototype implements Cloneable {
    private String name;

    public Prototype(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 关键是这个克隆方法
    public Prototype clone() {
        Prototype prototype = null;
        try {
            prototype = (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return prototype;
    }
}

具体原型类:

package com.hy.prototype;

public class ConcretePrototype extends Prototype {

    public ConcretePrototype(String name) {
        super(name);
        //System.out.println("构造方法");
    }

    public void show() {
        System.out.println(this.getName());
    }

}

测试类:

package com.hy.prototype;

public class Test {
    public static void main(String[] args) {
        ConcretePrototype cp1 = new ConcretePrototype("jame");
        cp1.show();
        for(int i = 0;i<2;i++){
            ConcretePrototype clonecp = (ConcretePrototype) cp1.clone();
            clonecp.show();
        }
    }
}

原型类需要具备两个条件:
 实现cloneable接口。作用是运行时通知虚拟机可以在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现这个接口可以实现拷贝,否则抛出CloneNotSupportedException异常。
 重写object类中的clone方法。Object中的clone方法作用是返回一个对象的拷贝,但是其作用域是protected类型,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。
原型模式的优点:
使用原型模式创建对象简化了对象的创建过程,而却比直接new一个对象在性能上好的多。因为object类的clone是一个本地方法,直接操作内存中的二进制流,特别是复制大对象时,原型模式优势更加明显。
应用场景:
需要重复的创建相似的对象时可以考虑使用原型模式。例如对象的创建过程比较复杂或者对象的创建的循环次数很多。

原型模式的注意事项:
 原型模式复制对象的时候不会调用类的构造方法,因为object类的clone方法是在内存中复制数据,因此不会调用到构造方法。而且clone方法直接无视构造方法的权限,所以原型模式和单例模式是冲突的。
深拷贝和浅拷贝
*1. Object类中的clone方法只会拷贝对象中的基本数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。

  1. 将原型模式的中的数组、容器对象、引用对象另行拷贝,即为深拷贝。*

PS:会发生深拷贝的有java中的8种基本类型以及他们的封装类型,另外还有String类型。其余的都是浅拷贝。
java提供的大部分的容器类都实现了Cloneable接口。所以实现深拷贝并不是特别困难。

例如----简历对象中添加工作经历的对象

工作经历类:

package com.hy.prototype;

public class Experience implements Cloneable{
    private String company;
    private int year;

    public Experience(String com, int year) {
        this.company = com;
        this.year = year;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    Get()set()略…
}

简历类:

package com.hy.prototype;

public class Resume implements Cloneable{
    private String name;
    private int age;
    private Experience exp;

    public Resume(String name, int age, Experience exp) {
        super();
        this.name = name;
        this.age = age;
        this.exp = exp;
    }

    @Override
    public String toString() {
        return "Resume [name=" + name + ", age=" + age + ", 经验: 在" + exp.getCompany()+"工作了"+exp.getYear()
                + "年 ]";
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Resume resume = (Resume) super.clone();
        resume.exp = (Experience) this.exp.clone();
        return resume;
    }

    Get()set()略…

}

测试类:

package com.hy.prototype;

public class Test {
    public static void main(String[] args) {
        try {
            Resume a = new Resume("aaa",12,new Experience("hyd",1));
            Resume b = (Resume) a.clone();
            System.out.println(a==b);
            System.out.println(a.getExp()==b.getExp());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

    }
}

输出结果均为false。如果Experience类不实现Cloneable接口,并且不在Resume类中clone方法实现Experience对象的克隆,则结果为false,ture。因为Experience并未实现深拷贝,导致引用对象相同,此时如果对克隆对象的Experience进行修改,则会影响原Resume对象。

1人推荐
随时随地看视频
慕课网APP