设计模式之原型模式

找工作时我们经常需要复印几份相同的简历。如果用编程来实现就是简单的复制粘贴,我们觉得很理所当然。

public class Resume {
    private String name;
    private String sex;
    private String age;
    private String timeArea;
    private String company;
    
    public Resume(String name){
        this.name = name;
    }
    //设置个人信息
    public void setPersonalInfo(String sex, String age){
        this.sex = sex;
        this.age = age;
    }
    //设置工作经历
    public void setWorkExperience(String timeArea, String company){
        this.timeArea = timeArea;
        this.company = company;
    }
    public void show(){
        System.out.println(name + " " + age + " " + sex);
        System.out.println("工作经历:" + timeArea + " " + company);
    }
    
}

public class Test{
    public static void main(String[] args){
        Resume resume1 = new Resume("zhangsan");
        resume1.setPersonalInfo("boy", "28");
        resume1.setWorkExperience("2016.3-2018.4", "xxxx         
                company");
        
        Resume resume2 = new Resume("wangmazi");
        resume2.setPersonalInfo("girl", "18");
        resume2.setWorkExperience("2015.3-2018.9", "xxxx 
                 company");
        
        resume1.show();
        resume2.show();
     }
}

可以看出我们需要几份简历就需要实例化几次。如果写错一个字,也得改很多次。那有没有一种更简洁的方式呢?那就是原型模式了

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

我们用原型模式来实现一下简历复制。

public class Resume3 implements Cloneable{
    private String name;
    private String sex;
    private String age;
    private WorkExperience we = new WorkExperience();
    
    public Resume3(String name){
        this.name = name;
    }
    //设置个人信息
    public void setPersonalInfo(String sex, String age){
        this.sex = sex;
        this.age = age;
    }
    //设置工作经历
    public void setWorkExperience(String timeArea, String company){
        we.setTimeArea(timeArea);
        we.setCompany(company);
    }
    public void show(){
        System.out.println(name + " " + age + " " + sex);
        System.out.println("工作经历:" + we.getTimeArea() + " " + we.getCompany());
    }
    public Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
    public static void main(String[] args) throws CloneNotSupportedException{
        Resume3 resume1 = new Resume3("zhangsan");
        resume1.setPersonalInfo("boy", "28");
        resume1.setWorkExperience("2016.3-2018.4", "xxxx company");
        
        //浅复制
        Resume3 resume2 = (Resume3)resume1.clone();
        resume2.setWorkExperience("2015.3-2018.9", "xxxx company");
        resume1.show();
        resume2.show();
    }
}

这样代码就清爽多了,复制一份简历也非常简单。通过new方式创建对象需要每次都执行构造函数,非常低效。所以一般在初始化的信息不发生变化的情况下,克隆是最好的办法,既隐藏了对象创建的细节,又大大提高了性能。

但这其中也有问题,clone方法是这样的,如果字段是值类型,则对改字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象,也就是说引用对象数据不会克隆过来。这就称为浅复制。从上面例子也可以看出,改变resume2的workExperience对象中的数据也会改变resume1的workExperience对象中的数据,因为他们是指向同一个引用。

那如何进行深复制呢?

public class Resume4 implements Cloneable{
    private String name;
    private String sex;
    private String age;
    private WorkExperience2 we;
    
    public Resume4(String name){
        this.name = name;
        we = new WorkExperience2();
    }
    public Resume4(WorkExperience2 workExperience) throws CloneNotSupportedException{
        this.we = (WorkExperience2) workExperience.clone();
    }
    //设置个人信息
    public void setPersonalInfo(String sex, String age){
        this.sex = sex;
        this.age = age;
    }
    //设置工作经历
    public void setWorkExperience(String timeArea, String company){
        we.setTimeArea(timeArea);
        we.setCompany(company);
    }
    public void show(){
        System.out.println(name + " " + age + " " + sex);
        System.out.println("工作经历:" + we.getTimeArea() + " " + we.getCompany());
    }
    public Object clone() throws CloneNotSupportedException{
        Resume4 resume = new Resume4(this.we);
        resume.name = this.name;
        resume.age = this.age;
        resume.sex = this.sex;
        return resume;
    }
    public static void main(String[] args) throws CloneNotSupportedException{
        Resume4 resume1 = new Resume4("zhangsan");
        resume1.setPersonalInfo("boy", "28");
        resume1.setWorkExperience("2016.3-2018.4", "xxxx company");
        
        //深复制
        Resume4 resume2 = (Resume4)resume1.clone();
        resume2.setWorkExperience("2015.4-2018.9", "xxxx company");
        resume1.show();
        resume2.show();
    }
}

这就是深复制,深复制把引用对象的变量指向复制过的对象,而不是原有的被引用的对象。我们发现如果引用中嵌套多层引用,深复制就变得很复杂,需要事先考虑清楚,小心处理。

posted @ 2018-07-19 20:50  Ericyshi  阅读(204)  评论(0编辑  收藏  举报