继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

【学习笔记】原型设计模式

Sivel
关注TA
已关注
手记 16
粉丝 9
获赞 50

原型模式

定义:

指原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象

特点 :

不需要知道任何创建细节,不调用构造函数

类型 :创建型

适用场景

  • 类初始化消耗较多资源
  • new产生一个对象需要非常繁琐的过程(数据准备,访问权限等)
  • 构造函数比较复杂
  • 循环体中产生大量的对象

优点

  • 比直接new一个对象性能高
  • 简化了创建过程

缺点

  • 必须配备克隆方法(有一个Cloneable接口,在jvm中具有这个的对象才有可能被拷贝。只有覆盖object的克隆方法才会一定被拷贝。因此这个也变成了一个风险点,毕竟我们可能会忘记。)
  • 对克隆复杂对象或对克隆出的复杂对象进行复杂改造时,容易造成风险
  • 深拷贝、浅拷贝要运用得当

我们模拟发送email的一个场景,假设new一个实体相当耗时。

@Data
public class Email {

    private String name;

    private String address;

    private String content;
}

public class EmailUtils {

    /**
     * 发送邮件
     */
    public static void sendmail(Email email) {
        String outContent = "向{0}同学,邮件地址:{1},邮件内容{2},发送邮件";

        System.out.println(MessageFormat.format(outContent, email.getName(), email.getAddress(), email.getContent()));
    }

    /**
     * 记录邮件
     */
    public static void saveOriginMailRRecord(Email email) {
        System.out.println("存储originMail记录,riginMailriginMail:" + email.getContent());
    }

}

图片描述

      通过打印结果我们可以得到可以轻松看出来,实际打印跟我们预想的并不符合。我们是想让saveOriginMailRRecord()这个方法打印“初始化模版”这句话的,但是最后结果却是打印了“恭喜中奖了哦”。
      按照往常的解决方法不是将24行的代码放到16行就是在for循环里面每次都new一个对象。因为假设了new的话是一个极其耗时的动作,所以我们在这里用原型模式去创建。我们只需要让Email实现Cloneable接口,然后重写一下clone方法即可。

@Data
public class Email implements Cloneable {

    private String name;

    private String address;

    private String content;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

然后我们改一下for循环里面的代码

  for (int i = 0; i < 10; i++) {
            //一个临时变量
            Email temp  = (Email) email.clone();
            temp.setName("姓名" + i);
            temp.setAddress("姓名" + i + "@XX.com");
            temp.setContent("恭喜中奖了哦");
            EmailUtils.sendmail(email);
        }

原型模式第二种常用方法

如果可以抽象出来,用这种方法也是可以的,不过大多数还是第一种颇多。

public abstract class AbstrractClass implements Cloneable {

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class A extends AbstrractClass{

    public static void main(String[] args) throws CloneNotSupportedException {
        A a =new A();
        a.clone();
    }
}

原型模式的坑

原型模式默认都是浅克隆,因此会出现下面的情况。图片描述
当我们改a的时候,最后发现b也被更改了。因此我们需要深克隆。所以我们需要对clone方法进行简单的更改。

public abstract class AbstrractClass implements Cloneable {

    @Override
    protected Object clone() throws CloneNotSupportedException {
        A a = (A) super.clone();
        
        //深克隆
        a.setLocalDate((Date) a.getLocalDate().clone());
        return a;
    }
}

图片描述
通过图片我们能看到对象已经不一样了。其实原型模式也是破坏单例模式的一种方案,这个就不贴图了,解决方案其实和解决反射破坏也很类似。

源码中原型模式的一些实现

图片描述

图片描述

网速不好我就不贴太多图了,其中还包括hashmap,redis等等。其中每个实现最重要的都是对于引用的判断,需要去对对象的引用进行思考。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP