简历复印——原型模式

简历复印——原型模式

小菜的简历,大鸟给小菜提出了一个要求:有一个简历类,必须有姓名,可以设置性别,年龄和工作经历,最终大鸟要三份简历。

简历代码的初步实现

  • 简历类
package prototype01;

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 setPersonInfo(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 display(){
        System.out.println(name + " " + sex + " " + age);
        System.out.println("工作经历:" + timeArea + " " + company);
    }

}
  • 客户端
package prototype01;

public class Client {
    public static void main(String[] args) {
        Resume resumeA = new Resume("小菜");
        resumeA.setPersonInfo("男","22");
        resumeA.setWorkExperience("2018 - 2019","XX公司");
        resumeA.display();

        Resume resumeB = new Resume("小菜");
        resumeB.setPersonInfo("男","22");
        resumeB.setWorkExperience("2018 - 2019","XX公司");
        resumeB.display();

        Resume resumeC = new Resume("小菜");
        resumeC.setPersonInfo("男","22");
        resumeC.setWorkExperience("2018 - 2019","XX公司");
        resumeC.display();
    }
}
/* out:
小菜 男 22
工作经历:2018 - 2019 XX公司
小菜 男 22
工作经历:2018 - 2019 XX公司
小菜 男 22
工作经历:2018 - 2019 XX公司
*/

三分简历需要实例化三次,这样的客户端代码很麻烦,如果我要200份简历,你就得实例化200次。

并且如果我设置参数错误的话就要修改好多次。

  • 想一想,为什么我们不这么写?
public static void main(String[] args) {
    Resume resumeA = new Resume("小菜");
    resumeA.setPersonInfo("男","22");
    resumeA.setWorkExperience("2018 - 2019","XX公司");

    Resume resumeB = resumeA;
    Resume resumeC = resumeA;

    resumeA.display();
    resumeB.display();
    resumeC.display();

}

这其实是传引用,也就是resumeA,resumeB,resumeC存的地址是相同的,指向同一对象,并没有复制三份。

  • 那有什么办法解决呢?
    • 其实Java给我们提供了Clone这样的方法。

原型模式

原型模式(Prototype),用原型实例指定创建对象的类型,并通过拷贝这些原型来创建新的对象。

在这里插入图片描述

原型模式就是从一个对象创建出另外一个可定制的对象,而且不需要知道任何细节。

  • 原型类
package prototype02;

public abstract class Prototype implements Cloneable{
    private String id;
    public Prototype(String id){
        this.id = id;
    }
    public String getId() {
        return id;
    }
    public abstract Prototype myClone() throws CloneNotSupportedException;
}
  • 具体原型类
package prototype02;

import java.util.Objects;

public class ConcretePrototype1 extends Prototype {
    public ConcretePrototype1(String id) {
        super(id);
    }

    /**
     * 浅克隆
     * clone出来的对象与原对象完全一致,
     * 引用变量还是原来对用的引用【拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。】
     * 即若对象中有引用数据类型的变量则无法拷贝
     * */
    @Override
    public Prototype myClone() throws CloneNotSupportedException {
        return (Prototype)this.clone();
    }

    // 子类重写Object中的clone
    // 本质上还是Object中的clone
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    /*
    * 在Java中,实现浅克隆通常意味着你需要重写对象的clone()方法。
    * Java中的Object类提供了一个默认的clone()方法,但这个默认实现是受保护的,
    * 因此你需要让你的类实现Cloneable接口(尽管这个接口是一个标记接口,没有任何方法),
    * 并且重写clone()方法以使其为public。
    * */

}
  • 客户端
package prototype02;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        ConcretePrototype1 p1 = new ConcretePrototype1("0721");
        ConcretePrototype1 c1 = (ConcretePrototype1)p1.myClone();

        System.out.println("clone:" + c1.getId());

        System.out.println(p1);
        System.out.println(c1);

    }
}
/* out:
clone:0721
prototype02.ConcretePrototype1@7291c18f
prototype02.ConcretePrototype1@34a245ab
*/

简历的原型实现

  • 简历类
package prototype03;

public class Resume implements Cloneable{

    private String name;
    private String sex;
    private String age;
    private String timeArea;
    private String company;

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

    // 设置个人信息
    public void setPersonInfo(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 display(){
        System.out.println(name + " " + sex + " " + age);
        System.out.println("工作经历:" + timeArea + " " + company);
    }


    // 浅克隆,实际上是Obeject.clone();
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
  • 客户端
package prototype03;


public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Resume resumeA = new Resume("小菜");
        resumeA.setPersonInfo("男","22");
        resumeA.setWorkExperience("2018 - 2019","XX公司");

        // 浅克隆,不能克隆引用对象。
        Resume c1 = (Resume)resumeA.clone();
        c1.setWorkExperience("1999 - 2000","YY公司");

        Resume c2 = (Resume)resumeA.clone();
        c2.setWorkExperience("2012 - 2013","ZZ公司");

        resumeA.display();
        c1.display();
        c2.display();

        System.out.println(resumeA);
        System.out.println(c1);
        System.out.println(c2);

    }
}
/* out:
小菜 男 22
工作经历:2018 - 2019 XX公司
小菜 男 22
工作经历:1999 - 2000 YY公司
小菜 男 22
工作经历:2012 - 2013 ZZ公司
prototype03.Resume@cc34f4d
prototype03.Resume@17a7cec2
prototype03.Resume@65b3120a
*/
  • 每new一次,都要执行一次构造函数,如果构造函数的执行时间很长,那么多次构造就显得很低效了。

  • 一般在初始化的信息不变的前提下,克隆是最好的方法。

  • 隐藏了对象创建的内部细节,也提高了性能。

  • 不用重新初始化对象,而是动态地获取对象运行时的状态。

浅克隆与深克隆

Object.clone():浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。

如果属性是基本类型,拷贝的就是基本类型的值;

如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。

即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。

  • 工作经历类
package prototype04;

public class WorkExperience {
    private String timeArea;
    private String company;

    public String getTimeArea() {
        return timeArea;
    }

    public void setTimeArea(String timeArea) {
        this.timeArea = timeArea;
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }
}
  • 简历类
package prototype04;

public class Resume implements Cloneable{

    private String name;
    private String sex;
    private String age;
    // 引用对象
    private WorkExperience workExperience;

    public Resume(String name){
        this.name = name;
        this.workExperience = new WorkExperience();
    }

    // 设置个人信息
    public void setPersonInfo(String sex,String age){
        this.sex = sex;
        this.age = age;
    }

    // 设置工作经历
    public void setWorkExperience(String timeArea,String company){
        workExperience.setTimeArea(timeArea);
        workExperience.setCompany(company);
    }

    public void display(){
        System.out.println(name + " " + sex + " " + age);
        System.out.println("工作经历:" + workExperience.getTimeArea() + " " + workExperience.getCompany());
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
  • 客户端
package prototype04;


public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Resume resumeA = new Resume("小菜");
        resumeA.setPersonInfo("男","22");
        resumeA.setWorkExperience("2018 - 2019","XX公司");

        // 浅克隆,不能克隆引用对象。
        Resume c1 = (Resume)resumeA.clone();
        c1.setWorkExperience("1999 - 2000","YY公司");

       Resume c2 = (Resume)resumeA.clone();
        c2.setWorkExperience("2012 - 2013","ZZ公司");

        resumeA.display();
        c1.display();
        c2.display();

        System.out.println(resumeA);
        System.out.println(c1);
        System.out.println(c2);

    }
}
/* out:
小菜 男 22
工作经历:2012 - 2013 ZZ公司
小菜 男 22
工作经历:2012 - 2013 ZZ公司
小菜 男 22
工作经历:2012 - 2013 ZZ公司
prototype04.Resume@17a7cec2
prototype04.Resume@65b3120a
prototype04.Resume@6f539caf
*/
  • 浅克隆:

  • clone出来的对象与原对象完全一致。

  • 引用变量还是原来对象的引用【拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。】

  • 即若对象中有引用数据类型的变量则无法拷贝。

  • 深克隆:

    • 会复制引用的对象,而不是指向原来的对象。

简历深复制的实现

  • 工作经历类
package prototype05;

// 实现Cloneable接口,表示有克隆的能力。
public class WorkExperience implements Cloneable{
    private String timeArea;
    private String company;

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

    public String getTimeArea() {
        return timeArea;
    }

    public void setTimeArea(String timeArea) {
        this.timeArea = timeArea;
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }
}
  • 简历类
package prototype05;

public class Resume implements Cloneable{

    private String name;
    private String sex;
    private String age;
    // 引用对象
    private WorkExperience workExperience;

    public Resume(String name){
        this.name = name;
        this.workExperience = new WorkExperience();
    }

    // 克隆引用对象
    private Resume(WorkExperience workExperience) throws CloneNotSupportedException {
        this.workExperience = (WorkExperience)workExperience.clone();
    }

    // 设置个人信息
    public void setPersonInfo(String sex,String age){
        this.sex = sex;
        this.age = age;
    }

    // 设置工作经历
    public void setWorkExperience(String timeArea,String company){
        workExperience.setTimeArea(timeArea);
        workExperience.setCompany(company);
    }

    public void display(){
        System.out.println(name + " " + sex + " " + age);
        System.out.println("工作经历:" + workExperience.getTimeArea() + " " + workExperience.getCompany());
    }

    // 深克隆(需要手动克隆)
    @Override
    public Object clone() throws CloneNotSupportedException {
        Resume resume = new Resume(this.workExperience);
        resume.setPersonInfo(this.sex,this.age);
        resume.setName(this.name);
        return resume;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/*
小菜 男 22
工作经历:2018 - 2019 XX公司
小菜 男 22
工作经历:1999 - 2000 YY公司
小菜 男 22
工作经历:2012 - 2013 ZZ公司
prototype05.Resume@17a7cec2
prototype05.Resume@65b3120a
prototype05.Resume@6f539caf
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值