设计模式-原型模式

定义

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

特点

不需要知道任何创建细节,不调用构造函数。

适用场景

  • 类初始化消耗较多资源。
  • new 产生的一个对象需要非常繁琐的过程(数据准备,访问权限等)。
  • 构造函数比较复杂的时候。
  • 循环体中生产大量的对象时。

优点

  • 性能比new 略高
  • 简化创建过程

缺点

  • 必须配备克隆方法

  • 对克隆复杂对象或对克隆出的对象进行改造时,容易引入危险(有深拷贝和浅拷贝相关的BUG)。

深拷贝与浅拷贝

简单点说 假设 A对象中一个属性为B,当A进行拷贝生成A1时同时A1里的属性为B1。但是当修改B时,B1跟着修改,这就是浅拷贝。

代码

这里我们就以发送邮件的逻辑为基础,做一个展示。

首先定义邮件类Mail
public class Mail implements Cloneable{

    private String name;

    private String content;

    private String address;

    //默认当前时间 由于是对象,在clone的时候会有深浅拷贝的问题
    private Date sendDate = new Date();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Date getSendDate() {
        return sendDate;
    }

    public void setSendDate(Date sendDate) {
        this.sendDate = sendDate;
    }

    @Override
    public String toString() {
        return "Mail{" +
                "name='" + name + '\'' +
                ", content='" + content + '\'' +
                ", address='" + address + '\'' +
                ", sendDate=" + sendDate +
                '}' + super.toString();
    }

    //注意这里,会涉及到深浅拷贝的问题
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Mail cloneMail = (Mail) super.clone();
        return cloneMail;
    }
}

这里我故意写了一个Date类型的属性,这样我们会更容易看出深浅拷贝BUG。

邮件发送类MailUtil
public class MailUtil {

    private static String CONTENT = "向{0},邮件地址:{1},发送内容: {2},发送时间:{3},发送成功!";
    public  static void sendMail(Mail mail) {
        System.out.println(MessageFormat.format(CONTENT,mail.getName(),mail.getAddress(),mail.getContent(),mail.getSendDate()));
    }
}

我们可以看到就是简单的输出。

发送启动类
public class PrototypeBootStrap {

    public static void main(String[] args) throws CloneNotSupportedException, InterruptedException {
        Mail mail = new Mail();
        mail.setName("钢铁侠");
        mail.setContent("我是你的粉丝");
        mail.setAddress("复仇者联盟");
        Mail cloneMail = (Mail) mail.clone();
        MailUtil.sendMail(mail);
        MailUtil.sendMail(cloneMail);
        //穿越一下
        mail.getSendDate().setTime(99999999999L);
        MailUtil.sendMail(mail);
        MailUtil.sendMail(cloneMail);
    }
}

我们看到 在第一次发送邮件之后,不小心穿越一下,设置了原对象(mail)的时间。正常我们理解既然cloneMailmail的拷贝。那么原对象修改,拷贝的对象里的值是不会变得。但是结果是这样吗?我们运行一下。

prototypecopy.jpg

这里我们就发现了浅拷贝的问题了。也是BUG率最容易出现的地方。

改进邮件类Mail

我们将邮件类中的 clone()方法改进一下。

@Override
protected Object clone() throws CloneNotSupportedException {
    Mail cloneMail = (Mail) super.clone();
    //避免浅拷贝
    cloneMail.sendDate = (Date) cloneMail.sendDate.clone();
    return cloneMail;
}

我们再来运行一下启动类。

prototypecopy1.jpg

这次的输出结果却是是我们想要的。

小结

在运用原型模式的时候,一定要多加小心,避免不必要的麻烦。希望我们可以在设计模式的海洋里找到属于自己的那片蓝。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 个性电子账单 现在电子账单越来越流行了,比如你的信用卡,没到月初的时候银行就会发一份电子邮件给你,说你这个月消费了...
    stayiwithime阅读 567评论 0 0
  • 前言 本文的主要内容如下: 介绍原型模式 示例Java语言的clone浅克隆与深克隆实现深克隆 原型模式的典型应用...
    小旋锋的简书阅读 2,053评论 0 2
  • 定义 原型模式属于对象的创建模式。通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建...
    步积阅读 1,666评论 0 2
  • 目录 本文的结构如下: 引言 什么是原型模式 浅克隆和深克隆 clone() 模式的结构 典型代码 代码示例 优点...
    w1992wishes阅读 642评论 0 0
  • 今天是什么日子 起床:6:30 就寝:9:30 天气:多云 心情:舒畅 纪念日:7月3日 叫我起床的不是闹钟是梦想...
    蓝小鱼_f201阅读 96评论 0 2

友情链接更多精彩内容