原型模式

原型模式(Prototype)

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

原型模式结构图

原型模式

原型模式初步探索

简单完成一份简历模板的撰写,最后要求三份一模一样的简历

Client Class

public class Client1 {
    public static void main(String[] args) {
        Resume1 a = new Resume1("大鸟");
        a.setPersonanInfo("男", 29);
        a.setWorkExperience("1998-2000", "xx公司");
​
        Resume1 b = new Resume1("大鸟");
        b.setPersonanInfo("男", 29);
        b.setWorkExperience("1998-2000", "xx公司");
​
        Resume1 c = new Resume1("大鸟");
        c.setPersonanInfo("男", 29);
        c.setWorkExperience("1998-2000", "xx公司");
​
        a.show();
        b.show();
        c.show();
    }
}

Resume Class

public class Resume1 {
    private String name;
    private String sex;
    private int age;
    private String timeArea;
    private  String company;
​
    /**
     * 初始化的时候初始不变的量
     * */
    public Resume1(String name) {
        this.name = name;
    }
​
    /**
     * 设置个人信息
     * */
    public void setPersonanInfo(String sex,int 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+" "+sex+" "+age);
        System.out.println(timeArea+" "+company);
    }
}

这样即完成了主体代码的编写。但是我们在这个过程中,发现Client创建了三次对象,那么可不可以将Client中的代码变成如下的结果呢?

    void test(){
        Resume1 a = new Resume1("大鸟");
        a.setPersonanInfo("男", 29);
        a.setWorkExperience("1998-2000", "xx公司");
​
        Resume1 b=a;
        b.setPersonanInfo("女",20);
        Resume1 c=a;
​
        a.show();
        b.show();
        c.show();
    }

可以明显的看到这两个是运行有不同的结果,在第一种的调用方式中,是存在三个不同的对象,其中任何一个值改变不会影响另外两个对象,他们之间是相互独立的。而在第二种调用方式中,实际上只是存在一个对象,这是传引用,三个指针同时指向一个对象。实际的问题就是值传递和引用传递的区别实际问题我们需要不同的简历

原型模式再探索

假设我们需要简历具有可复制的特点,那么简历就必须实现Cloneable接口,更改之后的类如下(实际这份代码就是原型模式中的浅复制)

Resume Class

public class Resume2 implements Cloneable {
    private String name;
    private String sex;
    private int age;
    private String timeArea;
    private  String company;
​
    public Resume2(String name) {
        this.name = name;
    }
​
    /**
     * 设置个人信息
     * */
    public void setPersonanInfo(String sex,int 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+" "+sex+" "+age);
        System.out.println(timeArea+" "+company);
    }
​
    @Override
    public Object clone() throws CloneNotSupportedException {
        Resume2 resume = null;
        try {
            resume = (Resume2) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return resume;
    }
}

Client Class

public class Client2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Resume2 a = new Resume2("大鸟");
        a.setPersonanInfo("男", 24);
        a.setWorkExperience("2000-2006", "zz公司");
​
        Resume2 b = (Resume2)a.clone();
        b.setPersonanInfo("男", 22);
        b.setWorkExperience("1998-2000", "yy公司");
​
        Resume2 c = (Resume2)a.clone();
        c.setPersonanInfo("男", 20);
        c.setWorkExperience("1996-1998", "xx公司");
​
        a.show();
        b.show();
        c.show();
    }
}
/**
 * 现在,若是我们需要更改某份简历,只要对这份简历做一定层次的修改即可以,这种修改不会影响到其他的简历,大大的满足了
 * 我们的需求
 *
 * */

原型模式之浅复制和深复制

Resume

/**
 * @className:Resume3
 * @Description: 一般的情况下,工作经历抽象为一个单独的类,让其工作,接下来我们便完成这样的工作
 * @author:TAO
 * @Date:2018/10/13 11:18
 */
public class Resume3 implements Cloneable{
    private String name;
    private String sex;
    private int age;
​
    /**
     * 设置工作经历的对象
     */
    private WorkExperience workExperience;
​
    public Resume3(String name) {
        this.name = name;
        workExperience=new WorkExperience();
    }
​
    /**
     * 设置个人信息
     * */
    public void setPersonanInfo(String sex,int age){
        this.sex=sex;
        this.age=age;
    }
​
    /**
     * 设置工作简历
     * */
    public void setWorkExperience(String timeArea,String company) {
        workExperience.workDatePub=timeArea;
        workExperience.companyPub=company;
    }
​
    /**
     * 显示简历内容
     * */
    public void show(){
        System.out.println(name+" "+sex+" "+age);
        System.out.println(workExperience.companyPub+" "+workExperience.workDatePub);
    }
​
    @Override
    public Object clone() throws CloneNotSupportedException {
        Resume3 resume = null;
        try {
            resume = (Resume3) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return resume;
    }
}

WorkExperience Class

public class WorkExperience {
    private String workDate;
    public String workDatePub;
    private String company;
    public String companyPub;
    
}

Client Class

public class Client3 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Resume3 a = new Resume3("大鸟");
        a.setPersonanInfo("男", 24);
        a.setWorkExperience("1998-2000","xx公司");
​
        Resume3 b = (Resume3)a.clone();
        b.setWorkExperience("1998-2006","YY公司");
        b.setPersonanInfo("男", 22);
​
​
        Resume3 c = (Resume3)a.clone();
        c.setPersonanInfo("男", 20);
        c.setWorkExperience("1998-2003","ZZ公司");
​
​
        a.show();
        b.show();
        c.show();
    }
}
/**
 * 分析结果可得到:name,sex,age 三个值会随着我们的设置而改变,而workExperience.workDatePub,workExperience.companyPub
 * 这两个值一直都是我们最后所设置的内容 ,根据前面的内容比较可知,这两个内容应该传递的是引用,都是指向同一个对象而不是值
 * 所以才会出现这样的结果,但是,这样的结果不是我们所需要的,那么应该怎么解决的?
 * 这里我们简单的解释一下原型模式中的浅复制和深复制
 *
 * 浅复制:被复制对象的所有变量都含有与原来对象相同的值,而所有对其他对象的引用都仍然指向原来的对象。
 * 但是,我们可能更需要一种需求:把要复制的对象所引用的对象都复制一遍。于是,我们开始学习“深复制”
 * 深复制:把引用对象的变量指向复制过的对象(相当于创建了一个新的对象),而不是原有的被引用的对象
 *
 * 说的简单一点:浅复制就是复制结构而不复制数据,深复制不但复制结构,也复制数据。
 * */

原型模式之深复制

Resume Class

public class Resume4 implements Cloneable {
    private String name;
    private String sex;
    private int age;
​
    /**
     * 设置工作经历的对象
     */
    private WorkExperience1 workExperience1;
​
    /**
     *  提供Clone方法调用的私有构造函数,以便克隆“工作经历的数据”
     * */
    private Resume4(WorkExperience1 workExperience1) throws CloneNotSupportedException {
        this.workExperience1 = (WorkExperience1) workExperience1.clone();
    }
​
    public Resume4(String name) {
        this.name = name;
        workExperience1=new WorkExperience1();
    }
​
​
    /**
     * 设置个人信息
     * */
    public void setPersonanInfo(String sex,int age){
        this.sex=sex;
        this.age=age;
    }
​
    /**
     * 设置工作简历
     * */
    public void setWorkExperience(String timeArea,String company) {
        workExperience1.setWorkDate(timeArea);
        workExperience1.setCompany(company);
    }
​
    /**
     * 显示简历内容
     * */
    public void show(){
        System.out.println(name+" "+sex+" "+age);
        System.out.println(workExperience1.getWorkDate()+" "+workExperience1.getCompany());
    }
​
    @Override
    protected Object clone() throws CloneNotSupportedException {
       Resume4 resume4=new Resume4(this.workExperience1);
       resume4.name=this.name;
       resume4.sex=this.sex;
       resume4.age=this.age;
       return resume4;
    }
}

WorkExperience Class

/**
 * @className:WorkExperience1
 * @Description: 工作经历,让工作经历也实现Cloneable接口
 * @Date:2018/10/13 12:22
 */
public class WorkExperience1 implements Cloneable {
    private String workDate;
    private String company;
​
    public String getWorkDate() {
        return workDate;
    }
​
    public void setWorkDate(String workDate) {
        this.workDate = workDate;
    }
​
    public String getCompany() {
        return company;
    }
​
    public void setCompany(String company) {
        this.company = company;
    }
​
    @Override
    public Object clone() throws CloneNotSupportedException {
        WorkExperience1 workExperience1=null;
        try {
            workExperience1=(WorkExperience1)super.clone();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return workExperience1;
    }
}

Client Class

public class Client4 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Resume4 a = new Resume4("大鸟");
        a.setPersonanInfo("男", 24);
        a.setWorkExperience("1998-2000","xx公司");
​
        Resume4 b = (Resume4) a.clone();
        b.setWorkExperience("1998-2006","YY公司");
        b.setPersonanInfo("男", 22);
​
        Resume4 c = (Resume4) a.clone();
        c.setPersonanInfo("男", 20);
        c.setWorkExperience("1998-2003","ZZ公司");
​
        a.show();
        b.show();
        c.show();
    }
}

小结

本文主要是讲解了原型模式的特点,以及原型模式的深复制、浅复制的实现,同时明白了传引用和传值的不同的部分。