原型模式

原型模式的简单程度仅次于单例模式,核心方法就一个clone(),在java中只需要实现接口Cloneable即可

原型模式通过把对象复制(clone)一遍,产生一个新的对象,和原有对象一样,然后再修改细节...这样就可以不用new一个新的对象了

之所以这样做,肯定是有道理的,比如可以避免线程安全问题、节约时间等等

原型模式类图

index.png

这种形式涉及到三个角色

(1)客户(Client)角色:客户类提出创建对象的请求。

(2)抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。

(3)具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

参考代码设计模式之蝉里的例子.. 背景的银行给大量用户发广告信息,这个信息有些部分相同,有些部分不同,并且需要发送数量较大,所以用原型模式解决

广告模板代码
package test;

public class AdvTemplate {
    
    private String advSubject = "XX银行国庆信用卡抽奖活动";
    
    private String advContext = "国庆抽奖活动通知:只要刷卡就送你一百万!...";

    public String getAdvSubject() {
        return advSubject;
    }

    public String getAdvContext() {
        return advContext;
    }
    
    
}
邮件类代码
package test;

public class Mail implements Cloneable {
    
    private String receiver;
    
    private String subject;
    
    private String appellation;
    
    private String context;
    
    private String tail;
    
    public Mail(AdvTemplate advTemplate) {
        
        this.context = advTemplate.getAdvContext();
        this.subject = advTemplate.getAdvSubject();
        
    }   

    @Override
    protected Object clone() throws CloneNotSupportedException {
        
        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 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;
    }
    
}

package test;

import java.util.ArrayList;

public class Thing implements Cloneable {

    private ArrayList<String> arrayList = new ArrayList<String>();

    @Override
    protected Thing clone() throws CloneNotSupportedException {
        
        Thing thing = null;
        
        try {
            thing = (Thing)super.clone();
            this.arrayList = (ArrayList<String>)this.arrayList.clone();
        } catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        
        return thing;
        
    }   
    
    public void setValue(String value) {
        this.arrayList.add(value);
    }
    
    public ArrayList<String> getValue() {
        return this.arrayList;
    }
        
}
场景类代码
package test;

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("XX银行版权所有");
        
        while( i < MAX_COUNT) {
            Mail cloneMail;
            try {
                cloneMail = (Mail)mail.clone();
                cloneMail.setAppellation(getRandString(5) + " 先生(女生)");
                cloneMail.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");
                sendMail(cloneMail);

            } catch (CloneNotSupportedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            i ++;
        }
        
        Thing thing = new Thing();
        thing.setValue("张三");
        
        try {
            Thing cloneThing = thing.clone();
            cloneThing.setValue("李四");
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        System.out.println(thing.getValue());
        
    }
    
    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();
    }

}

原型模式需要注意的就是深拷贝和浅拷贝的问题 在用java clone方法拷贝的时候,其对象内的数组和引用对象等都不拷贝,一个final类型的变量也不拷贝

比如对象中如果含有arrayList则不会拷贝 但加上thing.arrayList(ArrayList<String>)this.arrayList.clone(); 就成了深拷贝,就能拷贝了

clone和final是两个冤家,相爱相杀吧,这俩是有冲突的要注意

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏机器之心

PyTorch为何如此高效好用?来探寻深度学习框架的内部架构

选自blog.christianperone 作者:Christian S. Perone 机器之心编译 参与:思源、黄小天、李泽南 作为 Facebook 人...

3876
来自专栏编程

浅谈Java学习方法和后期面试技巧 含学习笔记

下面简单列举一下大家学习java的一个系统知识点的一些介绍: 一、java基础部分:java基础的时候,有些知识点是非常重要的,比如循环系列。For,while...

2018
来自专栏C语言及其他语言

[每日一题]选择法排序

谈到排序的方法,可以说是多种多样,比较常用的是冒泡法,而效率比较高的是快速法,今天给大家介绍的则是选择法 题目描述 用选择法对10个整数从小到大排序。 输入 ...

2966
来自专栏Android 开发者

[译] Kotlin 揭秘:理解并速记 Lambda 语法

在奥地利旅行期间,我参观了维也纳的奥地利国家图书馆。特别是国会大厅,这个令人惊叹的空间感觉就像印第安纳琼斯电影中的一些东西。房间周围的空间是这些门被装在架子上,...

870
来自专栏web前端教室

[先行者课程] -- 用js实现倒计时功能的业务逻辑

今天是2017年3月19号,周日,我们一起来学习“倒计时”这个前端“需求”。 一,看一下上周的作业,视差滚动的作业; 二,开始分享学习倒计时应用。 因为时间的关...

2705
来自专栏java一日一条

重构 改善既有代码的设计--笔记

查看一个类是否“过大”,这里有一个小技巧分享给大家。就是看两点:1)这个类实例变量太多,必然会有Duplicated Code(重复代码) 2)类内如果有太多代...

1104
来自专栏编程

Java 最困扰你的那些事

啊哈Reddit(某知名国外在线问答社区),没了你我们还能在哪里从鱼目混珠的网络中提炼真正的精华?就在这杂乱无章的论坛中,的的确确存在着这样一些精辟的讨论。 比...

2158
来自专栏AI研习社

博客 | LeetCode 617. Merge Two Binary Trees

在日常的业务系统开发中,通常架构设计>数据结构设计>算法设计,架构设计,重在理解业务场景,考虑用户规模和系统适配性的基础上,想清楚每个模块的职责,剩下的就是利用...

811
来自专栏java一日一条

哪些因素影响Java调用的性能?

这得从一个小故事说起。我在一个Java核心库的邮件列表中提交了一个修改 ——重写了一些本是 final 的方法。一石激起千层浪,这一改动引发了几番讨论。而其中一...

1201
来自专栏Albert陈凯

2018-11-08 杀死If Else switch case(策略模式+工厂模式+map)套餐 Kill 项目中的switch case

为了便于理解,举个没有业务逻辑的例子,基于这个例子上进行优化。 现在是12:47,举个饭后吃水果的例子哈哈哈(逃 假设我们可以选择的水果有香蕉、西瓜和苹果。吃香...

1853

扫码关注云+社区

领取腾讯云代金券