天天看点

设计模式-原型模式1. 原型模式

文章目录

  • 1. 原型模式
    • 1.1 定义
    • 1.2 使用场景
    • 1.3 模拟代码
    • 1.4 浅克隆和深克隆
    • 1.5 原型模式破坏单例
    • 1.6 应用源码解析

1. 原型模式

1.1 定义

  • 指原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。不需要知道任何创建的细节,不需要构造函数。
  • 该设计模式主要有四个组件(抽象Builder,实体Builder,产品,Director)。

1.2 使用场景

  • 类初始化消耗较多资源。
  • new产生的对象需要非常繁琐的过程。
  • 构造函数比较复杂。
  • 在循环体中产生大量对象时。

1.3 模拟代码

  • 以循环发送邮件为例,由于new出一个新邮件的代价是非常高的,所以采用clone方式进行创建新的Mail对象,采用克隆方式是不会调用类的构造器的。重点是要实现Cloneable接口,并重写Object的clone方法。
  • Mail类
package com.fukexin.design.pattern.creational.prototype;

public class Mail implements Cloneable{
    private String emailName;
    private String emailAddress;
    private String emailContent;

    public Mail()
    {
        System.out.println("Mail Class Constructor");
    }

    public String getEmailName() {
        return emailName;
    }

    public void setEmailName(String emailName) {
        this.emailName = emailName;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }

    public String getEmailContent() {
        return emailContent;
    }

    public void setEmailContent(String emailContent) {
        this.emailContent = emailContent;
    }

    @Override
    public String toString() {
        return "Mail{" +
                "emailName='" + emailName + '\'' +
                ", emailAddress='" + emailAddress + '\'' +
                ", emailContent='" + emailContent + '\'' +
                '}'+super.toString();
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        System.out.println("clone mail object");
        return super.clone();
    }
}

}
           
  • MailUtil类
package com.fukexin.design.pattern.creational.prototype;

import java.text.MessageFormat;

public class MailUtil {

    public static void sendMail(Mail mail)
    {
        String outputContent = "向{0}同学,邮件地址:{1},邮件内容:{2},发送邮件成功";
        System.out.println(MessageFormat.format(outputContent,mail.getEmailName(),mail.getEmailAddress(),mail.getEmailContent()));
    }

    public static void saveOriginMailRecord(Mail mail)
    {
        System.out.println("存储originMail记录:"+mail.getEmailContent());
    }
}
           
  • Test类
package com.fukexin.design.pattern.creational.prototype;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Mail mail=new Mail();
        mail.setEmailContent("初始化模板");
        for(int i=0;i<10;i++){
            Mail mailTemp= (Mail) mail.clone();
            mailTemp.setEmailName("同学"+i);
            mailTemp.setEmailAddress("同学"+i+"@jnu.com");
            mailTemp.setEmailContent("恭喜你被退学啦!");
            MailUtil.sendMail(mailTemp);
        }
        MailUtil.saveOriginMailRecord(mail);
    }
}
           

1.4 浅克隆和深克隆

  • 浅克隆:A对象中属性有值类型(int,double等等),也有引用类型,B对象是由A对象浅克隆的出来的对象(只重写clone方法,不进行其他修改),这是B对象中引用类性的引用与A对象中的引用类型的引用相同,当修改A对象引用类型的值时,B对象同样也会被修改。
  • 深克隆:A对象中属性有值类型(int,double等等),也有引用类型,B对象是由A对象深克隆的出来的对象(重写clone方法后,要对引用类型一一进行克隆),这是B对象中引用类性的引用与A对象中的引用类型的引用不同,当修改A对象引用类型的值时,B对象不会被修改。

1.5 原型模式破坏单例

  • 学完单例再来写!

1.6 应用源码解析

  • java.util.ArrayList实现了Cloneable接口,重写了clone方法,使用Arrays.copyOf

    将数组中的元素拷贝到克隆对象。

public Object clone() {
        try {
            ArrayList<?> v = (ArrayList)super.clone();
            v.elementData = Arrays.copyOf(this.elementData, this.size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException var2) {
            throw new InternalError(var2);
        }
    }
           
  • java.util.HashMap实现了Cloneable接口,重写了clone方法。
@HotSpotIntrinsicCandidate
    public Object clone() {
        HashMap result;
        try {
            result = (HashMap)super.clone();
        } catch (CloneNotSupportedException var3) {
            throw new InternalError(var3);
        }

        result.reinitialize();
        result.putMapEntries(this, false);
        return result;
    }
           
  • Mybatis中的CacheKey实现了Cloneable接口,重写了clone方法。(关于List的克隆,主要看里面的内容是什么,里面的是值类型,就会克隆一份新的。里面的是引用类型,就是同一个)。
public CacheKey clone() throws CloneNotSupportedException {
        CacheKey clonedCacheKey = (CacheKey)super.clone();
        clonedCacheKey.updateList = new ArrayList(this.updateList);
        return clonedCacheKey;
    }
           

继续阅读