大话设计模式之原型模式总结-java实现

本文介绍原型模式的实现方式及深浅复制的区别,通过简历类的实例展示如何利用原型模式快速创建对象,并深入探讨了深复制与浅复制在对象复制过程中的不同表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注:示例来自《大话设计模式》

现有需求如下 要求有一个简历类 必须要有姓名 可以设置性别和年龄 可以设置工作经历 最终我需要写三份简历 代码初步实现如下

简历类

package Test09;

//简历
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 Display()
    {
        System.out.println(name+" "+sex+" "+age);
        System.out.println(timeArea+" "+company);
    }

}

客户端代码

package Test09;

public class Program {

    public static void main(String[] args) {

        Resume a = new Resume("大鸟");
        a.SetPersonalInfo("男", "29");
        a.SetWorkExperience("1998-2000", "XX公司");

        Resume b = new Resume("大鸟");
        b.SetPersonalInfo("男", "29");
        b.SetWorkExperience("1998-2000", "XX公司");

        Resume c = new Resume("大鸟");
        c.SetPersonalInfo("男", "29");
        c.SetWorkExperience("1998-2000", "XX公司");

        a.Display();
        b.Display();
        c.Display();

    }

}

上面的代码 三份简历需要三次实例化 很麻烦 我们看看下面的写法

客户端代码

package Test09;

public class Program {

    public static void main(String[] args) {

        Resume a = new Resume("大鸟");
        a.SetPersonalInfo("男", "29");
        a.SetWorkExperience("1998-2000", "XX公司");

        Resume b = a;

        Resume c = a;

        a.Display();
        b.Display();
        c.Display();

    }

}

上面的代码 其实是传引用 而不是传值 这样做就如同是在b纸张和c纸张上写着简历在a处一样 没有实际的内容

接下来采用原型模式(Clone克隆)进行重构 代码如下

简历类

package Test09;

//简历
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 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 Display()
    {
        System.out.println(name+" "+sex+" "+age);
        System.out.println(timeArea+" "+company);
    }

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

}

客户端代码

package Test09;

public class Program {

    public static void main(String[] args) throws CloneNotSupportedException {

        Resume a = new Resume("大鸟");
        a.SetPersonalInfo("男", "29");
        a.SetWorkExperience("1998-2000", "XX公司");

        Resume b = (Resume)a.Clone();
        b.SetWorkExperience("1998-2006", "YY企业");

        Resume c = (Resume)a.Clone();
        c.SetPersonalInfo("男", "24");

        a.Display();
        b.Display();
        c.Display();

    }

}

clone()方法是这样 如果字段是值类型的 则对该字段执行逐位复制 如果字段是引用类型 则复制引用但不复制引用的对象 因此 原始对象及其复本引用同一对象 就是说如果简历类中有对象引用 那么引用的对象数据是不会被克隆过来的
例如我们单独写个工作经历类 里面有时间区间和公司名称属性 代码如下

工作经历类

package Test09;

//工作经历
public class WorkExperience {

    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;
    }

}

简历类

package Test09;

//简历
public class Resume implements Cloneable {

    private String name;
    private String sex;
    private String age;

    private WorkExperience work;

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

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

    //设置工作经历
    public void SetWorkExperience(String workDate, String company)
    {
        work.setWorkDate(workDate);
        work.setCompany(company);
    }

    //显示
    public void Display()
    {
        System.out.println(name+" "+sex+" "+age);
        System.out.println(work.getWorkDate()+" "+work.getCompany());
    }

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

}

客户端代码

package Test09;

public class Program {

    public static void main(String[] args) throws CloneNotSupportedException {

        Resume a = new Resume("大鸟");
        a.SetPersonalInfo("男", "29");
        a.SetWorkExperience("1998-2000", "XX公司");

        Resume b = (Resume)a.Clone();
        b.SetWorkExperience("1998-2006", "YY企业");

        Resume c = (Resume)a.Clone();
        c.SetPersonalInfo("男", "24");
        c.SetWorkExperience("1998-2003", "ZZ企业");

        a.Display();
        b.Display();
        c.Display();

    }

}

可以看到我给a b c三个引用设置工作经历 三个引用都指向了同一个对象 这叫做潜复制 被复制对象的所有变量都含有与原来的对象相同的值 而所有的对其他对象的引用都仍然指向原来的对象

但我们可能更需要这样的一种需求 把要复制的对象所引用的对象都复制一遍 比如刚才的例子 我们希望是a b c三个引用的对象都是不同的 即深复制 深复制把引用对象的变量指向复制过的新对象 而不是原有的被引用的对象 下面是深复制实现的代码

工作经历类

package Test09;

//工作经历
public class WorkExperience 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;
    }

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

}

简历类

package Test09;

//简历
public class Resume implements Cloneable {

    private String name;
    private String sex;
    private String age;

    private WorkExperience work;

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

    private Resume(WorkExperience work) throws CloneNotSupportedException
    {
        this.work = (WorkExperience)work.Clone();
    }

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

    //设置工作经历
    public void SetWorkExperience(String workDate, String company)
    {
        work.setWorkDate(workDate);
        work.setCompany(company);
    }

    //显示
    public void Display()
    {
        System.out.println(name+" "+sex+" "+age);
        System.out.println(work.getWorkDate()+" "+work.getCompany());
    }

    public Object Clone() throws CloneNotSupportedException
    {
        Resume obj = new Resume(this.work);

        obj.name = this.name;
        obj.sex = this.sex;
        obj.age = this.age;

        return obj;
    }

}

客户端代码

package Test09;

public class Program {

    public static void main(String[] args) throws CloneNotSupportedException {

        Resume a = new Resume("大鸟");
        a.SetPersonalInfo("男", "29");
        a.SetWorkExperience("1998-2000", "XX公司");

        Resume b = (Resume)a.Clone();
        b.SetWorkExperience("1998-2006", "YY企业");

        Resume c = (Resume)a.Clone();
        c.SetPersonalInfo("男", "24");
        c.SetWorkExperience("1998-2003", "ZZ企业");

        a.Display();
        b.Display();
        c.Display();

    }

}

以上为深复制实现

原型模式 用原型实例指定创建对象的种类 并且通过拷贝这些原型创建新的对象
原型模式其实就是从一个对象再创建另外一个可定制的对象 而且不需知道任何创建的细节 实现Cloneable这个接口就可以完成原型模式

一般在初始化的信息不发生变化的情况下 克隆是最好的办法 既隐藏了对象创建的细节 又对性能是大大的提高 它等于是不用重新初始化对象 而是动态地获得对象运行时的状态

缺点 原型模式无法和单例模式组合使用 使用原型模式时不能有final对象 浅复制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值