原型模式

一、定义:
用原型实例指定创建对象的种类, 并且通过拷贝这些原型创建新的对象。
通俗理解:不通过new关键字来产生一个对象, 而是通过对象复制来实现的模式就叫做原型模式。
二、类图:
这里写图片描述
三、代码:
MailTemplate.class

/**
 * 邮件模板类,定义邮件中的公共属性
 */
public class MailTemplate {

    private String title="xx银行国庆信用卡抽奖活动";//标题

    private String appelcation="先生(女士)";//称谓

    private String content="国庆抽奖活动通知:只要刷卡就送100万...";//内容

    private String tail="xx银行版权所有";//尾部

    public String getTitle() {
        return this.title;
    }

    public String getAppelcation(){
        return this.appelcation;
    }
    public String getContent(){
        return this.content;
    }

    public String getTail() {
        return this.tail;
    }

}

Mail.class

/**
 * 邮件类,定义一封邮件的所有属性.实现Cloneable接口,复写clone方法。
 */
public class Mail implements Cloneable{

    private String receiver;//邮件接收者

    private String appelcation;//称谓:女士/先生

    private String title;//邮件名称

    private String content;//邮件内容

    private String tail;//邮件末尾:XXX版权所有

    public Mail(MailTemplate template){//公共属性从模板类中获取
        if(template!=null){
            this.title=template.getTitle();
            this.appelcation=template.getAppelcation();
            this.content=template.getContent();
            this.tail=template.getTail();
        }
    }

    @Override
    protected Object clone(){
        // TODO Auto-generated method stub
        Mail mail=null;
        try {
            mail=(Mail) super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return mail;
    }

    public String getReceiver() {
        return receiver;
    }

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

    public String getAppelcation() {
        return appelcation;
    }

    public void setAppelcation(String appelcation) {
        this.appelcation = appelcation;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

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

    public String getTail() {
        return tail;
    }

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

}

Client.class

/**
 * 场景类,发送邮件
 */
public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub 
        int MAX_COUNT=5;//发送邮件的最大数量
        Mail mail=new Mail(new MailTemplate());//新建一个Mail实例,此实例含有公共的属性
        int i=0;
        while(i<MAX_COUNT){
            Mail cloneMail=(Mail) mail.clone();//通过克隆方式一个新的Mail实例
            cloneMail.setReceiver(getRandomStr(5)+"@"+getRandomStr(8)+".com");//改变mail实例的个性部分
            sendMail(cloneMail);
            i++;
        }
    }

    /**
     * 发送邮件
     */
    private static void sendMail(Mail mail){
        System.out.println("标题:"+mail.getTitle()+"\t内容:"+mail.getContent()+"\t收件人:"+mail.getReceiver()+"\t"+mail.getAppelcation()+"\t"+mail.getTail()+"\t发送成功...");
    }

    /**
     * 获取一串随机字符
     */
    private static String getRandomStr(int count){
        StringBuilder strBuilder=new StringBuilder();
        String origin="agakgahgadhgjkkhgauoiqrhiagnaigqergk";
        Random random=new Random();
        int i=0;
        while(i<count){
            strBuilder.append(origin.charAt(random.nextInt(origin.length())));
            i++;
        }
        return strBuilder.toString();
    }

}

注解:原型模式的核心是一个clone方法, 通过该方法进行对象的拷贝, Java提供了一个Cloneable接口来标示这个对象是可拷贝的, 为什么说是“标示”呢? 翻开JDK的帮助看看Cloneable是一个方法都没有的, 这个接口只是一个标记作用, 在JVM中具有这个标记
的对象才有可能被拷贝。 那怎么才能从“有可能被拷贝”转换为“可以被拷贝”呢? 方法是覆盖clone()方法, 是的, 你没有看错是重写clone()方法, 看看我们上面Mail类中的clone方法。
四、优点:
● 性能优良
原型模式是在内存二进制流的拷贝, 要比直接new一个对象性能好很多, 特别是要在一个循环体内产生大量的对象时, 原型模式可以更好地体现其优点。
● 逃避构造函数的约束
这既是它的优点也是缺点, 直接在内存中拷贝, 构造函数是不会执行的 。 优点就是减少了约束, 缺点也是减少了约束, 需要大家在实际应用时考虑。
五、使用场景:
● 资源优化场景
类初始化需要消化非常多的资源, 这个资源包括数据、 硬件资源等。
● 性能和安全要求的场景
通过new产生一个对象需要非常繁琐的数据准备或访问权限, 则可以使用原型模式。
● 一个对象多个修改者的场景
一个对象需要提供给其他对象访问, 而且各个调用者可能都需要修改其值时, 可以考虑使用原型模式拷贝多个对象供调用者使用。
六、注意事项:
1.深拷贝,浅拷贝
●Object类提供的方法clone只是拷贝本对象, 其对象内部的数组、 引用对象等都不拷贝, 还是指向原生对象的内部元素地址, 这种拷贝就叫做浅拷贝。(使用原型模式时, 引用的成员变量必须满足两个条件才不会被拷贝: 一是类的成员变量, 而不是方法内变量; 二是必须是一个可变的引用对象, 而不是一个原始类型或不可变对象。)若要实现深拷贝,则需要针对每个变量再分别拷贝,如下代码所示:

深拷贝:

/**
 * 邮件类,定义一封邮件的所有属性.实现Cloneable接口,复写clone方法。
 */
public class Mail implements Cloneable{

    private String receiver;//邮件接收者

    private String appelcation;//称谓:女士/先生

    private String title;//邮件名称

    private String content;//邮件内容

    private String tail;//邮件末尾:XXX版权所有

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

    public Mail(MailTemplate template){//公共属性从模板类中获取
        if(template!=null){
            this.title=template.getTitle();
            this.appelcation=template.getAppelcation();
            this.content=template.getContent();
            this.tail=template.getTail();
        }
    }

    @Override
    protected Object clone(){
        // TODO Auto-generated method stub
        Mail mail=null;
        try {
            mail=(Mail) super.clone();
            mail.arrayList=(ArrayList<String>) this.arrayList.clone();//Object的clone()方法是浅拷贝方法,不会拷贝类成员变量中不可变的数组,引用对象变量。若要实现深拷贝,则需要针对每个变量再分别拷贝。
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return mail;
    }

    public String getReceiver() {
        return receiver;
    }

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

    public String getAppelcation() {
        return appelcation;
    }

    public void setAppelcation(String appelcation) {
        this.appelcation = appelcation;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

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

    public String getTail() {
        return tail;
    }

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

}

这样就实现了完全的拷贝, 两个对象之间没有任何的瓜葛了, 你修改你的, 我修改我的, 不相互影响, 这种拷贝就叫做深拷贝。
●clone()方法与final关键字冲突(clone()方法要求对对象重新赋值,而final关键字不允许再修改值。),有final关键字修饰的成员变量就不能调用clone()方法,否则会报错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值