从原型模式getCopyBean的正确姿势

从原型模式开始诉说

何为原型模式?以实际应用场景来说,例如我们需要向客户批量发送邮件时,显然我们需要去引用一个具体的邮件模板,格式类似于“亲爱的xxxx(先生)女士: xxxx银行办理信用卡优惠…”之类的,之后再通过添加各个具体信息,发送具体邮件。而这个模板就是我们说的原型。

原型模式定义

原型模式定义:用原型实例()制定创建对象的种类,并通过拷贝这些原型创建新的对象
–摘自设计模式之禅

上代码

话不多说,以上文发邮件为例。我们的原型模式代码为

邮件原型的DTO代码

package com.example.mail.代理模式;

/**
 * 邮件
 */
public class Mail implements Cloneable {
    //收件人
    private String  receiver;
    //邮件名称
    private  String subject;
    //称谓
    private  String application;
    //邮件内容
    private  String contxt;
   //邮件尾部版权信息
    private  String tail;

    public Mail (AdvTemplate advTemplate){
        this.contxt = advTemplate.getAdvContext();
        this.subject = advTemplate.getAdvSubject();
    }

    @Override
    public Mail clone () {
        Mail mail = null;
       try {
           mail = (Mail) super.clone();
       }catch (CloneNotSupportedException e){
           e.printStackTrace();
       }
       return  mail;
    }
    public String getReceiver() {
        return receiver;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getApplication() {
        return application;
    }

    public void setApplication(String application) {
        this.application = application;
    }

    public String getContxt() {
        return contxt;
    }

    public void setContxt(String contxt) {
        this.contxt = contxt;
    }

    public String getTail() {
        return tail;
    }

    public void setTail(String tail) {
        this.tail = tail;
    }
}

此处为具体信内容的DTO

package com.example.mail.代理模式;

/**
 * 代理模式广告信模板
 */
public class AdvTemplate {
    //广告信名称
    private String advSubject = "光大银行春节抽奖活动";
    //广告信内容
    private String advContext = "春节抽奖活动通知:一刷卡就送一百万";

    public String getAdvSubject() {
        return advSubject;
    }

    public void setAdvSubject(String advSubject) {
        this.advSubject = advSubject;
    }

    public String getAdvContext() {
        return advContext;
    }

    public void setAdvContext(String advContext) {
        this.advContext = advContext;
    }
}

主线程,执行场景

package com.example.mail.代理模式;

import java.util.Random;

public class Client {
    //发送的邮件最大数量,可从数据库中获取
    private  static  int MAX_COUNT = 6;
    public  static  void  main (String[] args) {
        //模拟发送邮件
        int i = 0;
        //定义模板,可从数据库中获取
        Mail mail = new Mail(new AdvTemplate());
        mail.setTail("光大银行版权所有");
        while (i <MAX_COUNT) {
        //使用模板
            Mail cloneMail = mail.clone();
            cloneMail.setApplication(getRandString(5)+"先生(女士)");
            cloneMail.setReceiver(getRandString(5)+"@" +getRandString(8) + ".com");
        //发邮件
        sendMail(cloneMail);
        i++;
        }
    }
    //随机生成字符串
    public  static  String getRandString(int maxLength) {
        String source = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
        StringBuffer sb = new StringBuffer();
        Random random = new Random();
        for (int i=0 ; i <maxLength;i++){
            sb.append(source.charAt(random.nextInt(source.length())));

        }
        return  sb.toString();
    }
    public static void sendMail (Mail mail) {
        System.out.println("标题: "+ mail.getSubject() + "\t收件人: " + mail.getReceiver() + "\t ...发送成功");
    }
}

说明:原型模式最大的特点便是提供一个clone方法,让你去拷贝原始对象。
嗯,有的同学要是问为啥用clone,我可以这么去用对象啊

// 新手同学的写法
 Mail cloneMail = new Mail();
 cloneMail = mail;

这么做的小伙伴可以去试试打印下mail里的值,随着你之后对cloneMail的操作(比如赋值),你也会改变mail这个原型里的值。要是再来个多线程,那么相信我,mail里的值会被改到妈妈都不认识。而其他使用这个原型的地方也会。。。。
在这里插入图片描述

结论

从上述例子我们可以get到当我们需要以一个bean为模板的时候(既然是模板,那肯定是不能在模板里进行修改),我们正确的copy方式是使用clone()的方式去拷贝bean里的属性而非使用引用的方式去指向模板,牢记模板是不可以被修改的。这也是一些新手小白产生一些离奇bug的原因。当然老湿机肯定觉得我说了一大顿废话。
在这里插入图片描述

注意事项

clone()f方法就万事大吉了?你想偷懒,java也想偷懒,于是就尴尬了。在java中使用clone()方法时请注意java是不会将你的非基本数据类型的属性copy过来(没错,也就是bean中还有bean的,包含的bean属性不会copy过来)。List也不会
因此clone时得注意这点,如果拷贝过来,那么bean中重写clone方法的时候添加clone需要的bean属性逻辑。有点绕了,直接看代码吧。

   //定义一个List无法被clone
    private ArrayList<String> arrayList =new ArrayList<>();
    
    @Override
    public Mail clone () {
        Mail mail = null;
       try {
           mail = (Mail) super.clone();
           //划重点。写上clone无法被copy的属性的拷贝逻辑,此处list无法被拷贝,因此加上List的copy逻辑
           this.arrayList = (ArrayList<String>) this.arrayList.clone();
       }catch (CloneNotSupportedException e){
           e.printStackTrace();
       }
       return  mail;
    }

顺道说下这便是所谓的深拷贝,关于深浅拷贝之间的介绍,之后我会继续更新文章详解的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值