设计模式之原型模式

 一、介绍

在面向对象系统中,使用原型模式来复制一个对象自身,从而克隆出多个与原型对象一模一样的对象。

另外在软件系统中,有些对象的创建过程较为复杂,而且有时候需要频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在。

1.1 定义

GOF给出的原型模式定义如下:

Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype. (使用原型实例指定将要创建的对象类型,通过复制这个实例创建新的对象。)

1.2 模式分析


在原型模式结构中定义了一个抽象原型类,所有的Java类都继承自java.lang.Object,而Object类提供一个clone()方法,可以将一个Java对象复制一份。因此在Java中可以直接使用Object提供的clone()方法来实现对象的克隆,Java语言中的原型模式实现很简单。

能够实现克隆的Java类必须实现一个标识接口Cloneable,表示这个Java类支持复制。如果一个类没有实现这个接口但是调用了clone()方法,Java编译器将抛出一个CloneNotSupportedException异常。

注意: java.lang.Cloneable 只是起到告诉程序可以调用clone方法的作用,它本身并没有定义任何方法。

在使用原型模式克隆对象时,根据其成员对象是否也克隆,原型模式可以分为两种形式:深克隆 和 浅克隆 。

 

二、实现

下图是原型模式的UML结构图:

Prototype模å¼çç±»å¾

下面以一个例子来说明,利用原型模式来模拟复印简历:

//简历类
public class Resume implements Cloneable {
    private String name;
    private String sex;
    private String age;
    private WorkExperience work = new WorkExperience();

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

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

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

//工作经历类  
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;
    }
}

//main方法
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Resume a = new Resume("张三");
        a.setPersonalInfo("男", "29");
        a.setWorkExperience("1998-2000", "XX公司");

        Resume b = a.clone();
        b.setWorkExperience("1998-2006", "YY公司");

        Resume c = a.clone();
        c.setWorkExperience("1998-2003", "ZZ公司");

        a.display();
        b.display();
        c.display();
    }
}


输出信息:

张三     男     29
工作经历:1998-2003 ZZ公司
张三     男     29
工作经历:1998-2003 ZZ公司
张三     男     29
工作经历:1998-2003 ZZ公司

这里我们可以看到工作经验都变成了最后更改的信息,原因是WorkExperience是一个类,即引用类型而不是值类型,在复制的时候只是复制了它的引用,只是增加了一个指针指向已存在的内存地址。所以在修改它的时候会导致其它引用到它的地方也会改变。

那么如何解决这个问题呢,我们需要改写Resume 类和 WorkExperience类

//简历类
public class Resume implements Cloneable {
    private String name;
    private String sex;
    private String age;
    private WorkExperience work = new WorkExperience();

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

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

    @Override
    public Resume clone() {
        Resume obj = new Resume(name);
        obj.sex = this.sex;
        obj.age = this.age;
        obj.work = work.clone();

        return obj;

    }
}




//工作经历类
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;
    }

    @Override
    public WorkExperience clone() {
        try {
            return (WorkExperience) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}


//main方法
public class Main {
    public static void main(String[] args) {
        Resume a = new Resume("李四");
        a.setPersonalInfo("男", "20");
        a.setWorkExperience("1998-2000", "XX公司");

        Resume b = a.clone();
        b.setWorkExperience("1998-2006", "YY公司");

        Resume c = a.clone();
        c.setPersonalInfo("男", "24");

        a.display();
        b.display();
        c.display();
    }
}

输出信息:
李四     男     20
工作经历:1998-2000 XX公司
李四     男     20
工作经历:1998-2006 YY公司
李四     男     24
工作经历:1998-2000 XX公司

我们可以看到三份简历是不同的。

 

三、 模式优缺点分析


3.1 原型模式的优点:

  • 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过一个已有实例可以提高新实例的创建效率。
  • 可以动态增加或减少产品类。
  • 原型模式提供了简化的创建结构。
  • 可以使用深克隆的方式保存对象的状态。

3.2 原型模式的缺点:

  • 需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了“开闭原则”。
  • 在实现深克隆时需要编写较为复杂的代码。

 

四、原型模式的实际应用案例

4.1 使用场景:

  1.  资源优化场景。
  2. 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
  3. 性能和安全要求的场景。
  4. 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
  5. 一个对象多个修改者的场景。
  6. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
  7. 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。

 

4.2 原型模式的实际应用案例

  1. 原型模式应用于很多软件中,如果每次创建一个对象要花大量时间,原型模式是最好的解决方案。很多软件提供的复制(Ctrl + C)和粘贴(Ctrl + V)操作就是原型模式的应用,复制得到的对象与原型对象是两个类型相同但内存地址不同的对象,通过原型模式可以大大提高对象的创建效率。
  2. 在Struts2中为了保证线程的安全性,Action对象的创建使用了原型模式,访问一个已经存在的`Action对象时将通过克隆的方式创建出一个新的对象,从而保证其中定义的变量无须进行加锁实现同步,每一个Action中都有自己的成员变量,避免Struts1因使用单例模式而导致的并发和同步问题。
  3. 在Spring中,用户也可以采用原型模式来创建新的bean实例,从而实现每次获取的是通过克隆生成的新实例,对其进行修改时对原有实例对象不造成任何影响。
内容概要:《2024年中国城市低空经济发展指数报告》由36氪研究院发布,指出低空经济作为新质生产力的代表,已成为中国经济新的增长点。报告从发展环境、资金投入、创新能力、基础支撑和发展成效五个维度构建了综合指数评价体系,评估了全国重点城市的低空经济发展状况。北京和深圳在总指数中名列前茅,分别以91.26和84.53的得分领先,展现出强大的资金投入、创新能力和基础支撑。低空经济主要涉及无人机、eVTOL(电动垂直起降飞行器)和直升机等产品,广泛应用于农业、物流、交通、应急救援等领域。政策支持、市场需求和技术进步共同推动了低空经济的快速发展,预计到2026年市场规模将突破万亿元。 适用人群:对低空经济发展感兴趣的政策制定者、投资者、企业和研究人员。 使用场景及目标:①了解低空经济的定义、分类和发展驱动力;②掌握低空经济的主要应用场景和市场规模预测;③评估各城市在低空经济发展中的表现和潜力;④为政策制定、投资决策和企业发展提供参考依据。 其他说明:报告强调了政策监管、产业生态建设和区域融合错位的重要性,提出了加强法律法规建设、人才储备和基础设施建设等建议。低空经济正加速向网络化、智能化、规模化和集聚化方向发展,各地应找准自身比较优势,实现差异化发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值