设计模式二——原型模式

来源:互联网 发布:腾讯高级php面试题 编辑:程序博客网 时间:2024/06/06 00:34

写在前面:对于原型模式的介绍,网上有很多。但是给我的感觉,有些介绍并不是在单纯的介绍原型模式本身的意义,而是附加了其他的设计模式。至少我在看过很多文章之后,不仅未清晰的了解原型模式的本质,反而愈发感觉糊里糊涂。当然,这或许是我个人还没达到理解这种模式的水平。
本文关于原型模式的介绍,基本是出于我个人依据定义的理解。或许是正确的,或许存在谬误,欢迎大家留言指正讨论。


目录

      • 目录
    • 一模式定义分析
      • 1实现对象复制之前先回顾一下以下知识点
      • 2哪些场景下应该考虑使用复制的模式呢
      • 3复制在哪里操作需要注意什么
    • 二代码实现
          • 1原型类代码
          • 2调用类代码
    • 三补充说明
    • 四参考文章

首先看下原型模式的定义:

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
Prototype原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

一、模式定义分析

通过上面的定义,得到的关键词是:对象复制。那我们就从对象和复制展开来讨论。

1、实现对象复制之前先回顾一下以下知识点:

  1. 在Java中,对象实例的创建一般都要通过new关键字,需要通过构造函数来实例化。既然要复制,可能要避开这个限制。
  2. 在Java中,创建的对象除去基本数据类型的非包装类、字符串对象(在JDK7之前,待考证)等,绝大多数的对象都是在堆内存中创建的。复制,就需要在内存空间中创建出一个独立的对象出来。
  3. 在Java中,提供了语言级别的复制支持,那就是Cloneable接口。这个接口是个标记接口,里面并没有要实现的方法。因为所有的对象都隐式的继承自Object类,Object类中有一个clone方法。这个clone方法有2个限制:①方法修饰符是protected,无法在非继承类内部使用,所以要在重写时把修饰符改为public。②如果没有实现Cloneable接口而直接调用clone方法,会报错。
  4. 对象中既有基本数据类型的成员变量,也有可能有引用类型的成员变量,拷贝方式肯定有区别。所以需要了解浅拷贝和深拷贝的概念。

2、哪些场景下应该考虑使用复制的模式呢?

因为和复制做对比的,主要是通过new关键字来创建对象,所以来看下new可能会遇到的性能问题。

①当new对象需要大量繁琐的准备工作时,复制会提高性能。

示例场景public Demo getDemoInstance() {    Object obj = prepareObject();// 创建对象前需要执行一些耗时操作    Demo demo = new Demo(obj);}public Demo(Object obj) {    // 解析配置、初始化环境、设置变量等等操作}

②当需要多次重复的调用new关键字执行构造函数时,累积的时间损耗也是可以考虑的优化点。

for(int i=0; i<1000000; i++) {    Demo demo = new Demo(); // 每次都要新建对象,而new又比较耗时的时候    handle(demo);}

③当一个对象创建耗时,单实例又存在并发安全问题时,也可以考虑复制一份。

写到这里忍不住想起ThreadLocal类,这个号称为每个线程拷贝一份副本的类是怎么实现的?深拷贝还是浅拷贝呢?拷贝时如果泛型里的类没有实现Cloneable接口会怎样呢?回头再去看看...

3、复制在哪里操作?需要注意什么?

  • 尽量减少new对象的地方,如果系统中大量通过new创建的对象,那么复制也就没啥意义了
  • 复制需要在用到原型类对象的地方来操作

二、代码实现:

1、原型类代码
public class Prototype implements Cloneable {    private String name;    private int age;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }
2、调用类代码
public class PrototypeClient {    public static void main(String[] args) throws CloneNotSupportedException {        Prototype raw = new Prototype();        for (int i=0; i<1000; i++) {            Prototype clone = (Prototype) raw.clone();            System.out.println(clone);        }    }}

三、补充说明:

综上,复制之前我们需要先有一个现成的对象,但是这个现成的对象数量不宜过多,否则就失去了复制的意义。原始对象可以考虑使用缓存的方式、单例模式等。

四、参考文章:

原型模式|菜鸟教程
设计模式之原型模式
【JAVA】设计模式之原型模式的使用分析

0 0