设计模式原则13----原型模式

个人博客:打开链接

个性化电子账单

电子账单系统一般包括:账单分析、账单生成器、广告信管理、发送队列管理、发送机、退信处理、报表管理等功能。那既然是广告信,肯定需要一个模板,然后从数据库中把客户的信息一个一个地取出来,放到模板中生成一份完整的邮件,然后扔给发送机进行发送处理,类图为:
这里写图片描述
广告信模板代码:

public class AdvTemplate {

    //广告信名称
    private String advSubject = "XXX银行国庆信用卡抽奖活动";
    //广告信内容
    private String advContext = "国庆抽奖活动通知:只要刷卡就送你 一百万!...";

    //获得广告信的名称
    public String getAdvSubject() {
        return this.advSubject;
    }

    //获得广告信的内容
    public String getAdvContext() {
        return this.advContext;
    }
}

邮件类代码:


public class Mail {

    //收件人
    private String receiver;
    //邮件名称
    private String subject;
    //称谓
    private String appellation;
    //邮件内容
    private String context;
    //邮件的尾部,一般都是加上"XXX版权所有"等信息
    private String tail;
    //构造函数
    public Mail(AdvTemplate advTemplate){
        this.context = advTemplate.getAdvContext();
        this.subject = advTemplate.getAdvSubject();
    }
    //以下为getter和setter方法
    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 getAppellation() {
        return appellation;
    }
    public void setAppellation(String appellation) {
        this.appellation = appellation;
    }
    public String getContext() {
        return context;
    }
    public void setContext(String context) {
        this.context = context;
    }
    public String getTail() {
        return tail;
    }
    public void setTail(String tail) {
        this.tail = tail;
    }
}

场景类:


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("XXX银行版权所有");
        while(i < MAX_COUNT){
            //以下是每封邮件不同的地方
            mail.setAppellation(getRandString(5) + " 先生(女士)");
            mail.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");
            //然后发送邮件
            sendMail(mail);
            i++;
        }
    }
    //发送邮件
    public static void sendMail(Mail mail){
        System.out.println("标题:" + mail.getSubject() + "\t收件人:" 
                            + mail.getReceiver() + "\t...发送成功!");
    }
    //获得指定长度的随机字符串
    public static String getRandString(int maxLength){
        String source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuffer sb = new StringBuffer();
        Random rand = new Random();
        for(int i = 0; i < maxLength; i++){
            sb.append(source.charAt(rand.nextInt(source.length())));
        }
        return sb.toString();
    }
}

这是一个线程在运行,也就是你发送邮件是单线程的,假如发送一封邮件用时0.02秒,这已经够小了吧,那600万封邮件需要33个小时,这用时太长了,使我们无法接受的。所以,我们把sendMail改为多线程,来看一下修改过后的类图:
这里写图片描述
增加了一个Cloneable接口,Java自带的一个接口,Mail实现了这个接口,在Mail类中覆写clone()方法,代码清单如下:


public class Mail implements Cloneable{

    //收件人
    private String receiver;
    //邮件名称
    private String subject;
    //称谓
    private String appellation;
    //邮件内容
    private String context;
    //邮件的尾部,一般都是加上"XXX版权所有"等信息
    private String tail;
    //构造函数
    public Mail(AdvTemplate advTemplate){
        this.context = 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;
    }
    //以下为getter和setter方法
    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 getAppellation() {
        return appellation;
    }
    public void setAppellation(String appellation) {
        this.appellation = appellation;
    }
    public String getContext() {
        return context;
    }
    public void setContext(String context) {
        this.context = context;
    }
    public String getTail() {
        return tail;
    }
    public void setTail(String tail) {
        this.tail = tail;
    }
}

修改后的场景类:


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("XXX银行版权所有");
        while(i < MAX_COUNT){
            //以下是每封邮件不同的地方
            Mail cloneMail = mail.clone();
            cloneMail.setAppellation(getRandString(5) + " 先生(女士)");
            cloneMail.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");
            //然后发送邮件
            sendMail(cloneMail);
            i++;
        }
    }
    //发送邮件
    public static void sendMail(Mail mail){
        System.out.println("标题:" + mail.getSubject() + "\t收件人:" 
                            + mail.getReceiver() + "\t...发送成功!");
    }
    //获得指定长度的随机字符串
    public static String getRandString(int maxLength){
        String source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuffer sb = new StringBuffer();
        Random rand = new Random();
        for(int i = 0; i < maxLength; i++){
            sb.append(source.charAt(rand.nextInt(source.length())));
        }
        return sb.toString();
    }
}

这种不通过new关键字来产生一个对象,而是通过对象复制来实现的模式就叫做原型模式。

原型模式的定义

原型模式(Prototype Pattern): 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标识这个对象是可拷贝的。
原型模式的通用代码:

public class PrototypeClass implements Cloneable{

    //覆写父类Object方法
    @Override
    public PrototypeClass clone(){
        PrototypeClass prototypeClass = null;
        try {
            prototypeClass = (PrototypeClass) super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return prototypeClass;
    }
}

实现一个接口,然后重写clone()方法,就完成了原型模式。

原型模式的优点

1、性能优良
原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现优点
2、逃避构造函数的约束。
它不再需要构造函数,这既是它的优点,也是它的缺点

使用场景

1、资源优化场景
类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等
2、性能和安全要求
通过new一个对象要非常繁琐的数据准备或访问权限,则可以使用原型模式
3、一个对象提供给多个修改者
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑原型模式拷贝多个对象供调用者使用。

注意事项

  • 当clone一个对象时,构造函数不会被执行。Object类的clone()方法的原理是从内存中(具体来说就是堆内存)以二进制流的方式进行拷贝,从新分配一个内存块,那构造函数没有被执行也是非常正常的了。
  • Object类提供的方法clone只是拷贝对象,其内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝叫做浅拷贝。
  • 让ArrayList成为深拷贝:this.arrayList = (ArrayList)this.arrayList.clone();
  • 要是有clone()方法,类的成员变量上不要增加final关键字。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

勤奋的凯尔森同学

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值