• 原型模式


    原型模式算是JAVA中最简单的设计模式了,原因是因为它已经被提供了语言级的支持,但是如果提到它的实现原理,又是最复杂的一个设计模式。

    (1)先看一下原型模式的UML类图

      其中,Prototype是一个原型的抽象类或借口,它里面有一个共有方法,叫clone。ConcretePrototype1与ConcretePrototype2是两个具体的实例,继承或实现了Prototype。这就对应了定义中用原型实例指定创建对象的种类。Client是客户端类,它与Prototype是关联的关系,即在Client类的实例中,有Prototype的对象。客户端可以通过调用Prototype的clone方法来对实现了Prototype的ConcretePrototype1或ConcretePrototype2的对象进行复制来创建新对象,这样比new会有更高的执行效率。

    (2)下面我们先来看看这个又简单又复杂的设计模式的定义

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

    定义比较简单,总结一下是通过实例指定种类,通过拷贝创建对象。

    在JAVA语言中使用原型模式是非常简单的,这是因为Object类当中提供了一个本地方法clone,而JAVA中的任何类只要实现了Cloneable标识接口,就可以使用clone方法来进行对象的拷贝。

    我们写一个简单的实例来测试一下,很简单:

    public class Prototype implements Cloneable {
     
            private int x;
     
            private int y;
     
            private int z;
     
            public Prototype() {
     
                    this.x = 2;
     
                    this.y = 3;
     
                    this.z = 4;
     
            }
     
            public void change() {
     
                    this.x = 9;
     
                    this.y = 8;
     
                    this.z = 7;
     
            }
     
            public Prototype clone() {
     
                    Object object = null;
     
                    try {
     
                            object = super.clone();
     
                    } catch (CloneNotSupportedException exception) {
     
                            throw new RuntimeException(exception);
     
                    }
     
                    return (Prototype) object;
     
            }
     
            public String toString() {
     
                    return "[" + x + "," + y + "," + z + "]";
     
            }
     
            public static void main(String[] args) {
     
                    Prototype prototype1 = new Prototype();
     
                    prototype1.change();
     
                    System.out.println(prototype1);
     
                    Prototype prototype2 = prototype1.clone();
     
                    System.out.println(prototype2);
     
            }
     
    }
     

    输出结果:

      [9,8,7]

      [9,8,7] 

       从输出结果可以看出来,clone方法将prototype1复制了一个,然后赋给了prototype2,这就像复制粘贴一样。值得注意的是,在使用Object.clone()方法去拷贝一个对象时,构造方法是不被执行的,否则prototype2实例中x,y,z的值应该为2,3,4才对,如果你觉得不够直观,可以在构造方法里写一个输出语句试试。

    (3)从原型模式的使用方式不难推断出,原型模式常使用于以下场景:

           1、对象的创建非常复杂,可以使用原型模式快捷的创建对象。

           2、在运行过程中不知道对象的具体类型,可使用原型模式创建一个相同类型的对象,或者在运行过程中动态的获取到一个对象的状态。

    对于clone方法,它执行的是浅拷贝,也就是说如果是引用类型的属性,则它不会进行拷贝,而是只拷贝引用。

           看下面这个简单的测试,就能看出来了。

    class Field implements Cloneable{       
     
            private int a;
     
            public int getA() {
     
                    return a;
     
            }
     
            public void setA(int a) {
     
                    this.a = a;
     
            }
     
           
     
            protected Field clone() {
     
                    Object object = null;
     
                    try {
     
                            object = super.clone();
     
                    } catch (CloneNotSupportedException exception) {
     
                            throw new RuntimeException(exception);
     
                    }
     
                    return (Field) object;
     
            }
     
           
     
    }
     
     
     
    public class DeepPrototype implements Cloneable {
     
            private int x;
     
            private int y;
     
            private int z;
     
            private Field field;
     
            public DeepPrototype() {
     
                    this.x = 2;
     
                    this.y = 3;
     
                    this.z = 4;
     
                    this.field = new Field();
     
                    this.field.setA(5);
     
            }
     
           
     
            public Field getField() {
     
                    return field;
     
            }
     
            protected DeepPrototype clone() {
     
                    Object object = null;
     
                    try {
     
                            object = super.clone();
     
                            ((DeepPrototype)object).field = this.field.clone();
     
                    } catch (CloneNotSupportedException exception) {
     
                            throw new RuntimeException(exception);
     
                    }
     
                    return (DeepPrototype) object;
     
            }
     
            public String toString() {
     
                    return "[" + x + "," + y + "," + z + "," + field.getA() + "]";
     
            }
     
            public static void main(String[] args) {
     
                    DeepPrototype prototype1 = new DeepPrototype();
     
                    System.out.println(prototype1);
     
                    System.out.println(prototype1.getField());
     
                    DeepPrototype prototype2 = prototype1.clone();
     
                    System.out.println(prototype2);
     
                    System.out.println(prototype2.getField());
     
            }
     
    }

    输出结果:

      [2,3,4,5]

      com.prototype.Field@a90653

      [2,3,4,5]

      com.prototype.Field@de6ced

    (4)下面我们来看下原型模式的主要优点:

            1、由于clone方法是由虚拟机直接复制内存块执行,所以在速度上比使用new的方式创建对象要快。

            2、可以基于原型,快速的创建一个对象,而无需知道创建的细节。

            3、可以在运行时动态的获取对象的类型以及状态,从而创建一个对象。

      然而原型模式的缺点也是相当明显的,主要的缺点就是实现深度拷贝比较困难,需要很多额外的代码量。

           不过实际当中我们使用原型模式时,也可以写一个基类实现Cloneable接口重写clone方法,然后让需要具有拷贝功能的子类继承自该类,这是一种节省代码量的常用方式。像上面的例子一样,如果一个类继承自Prototype,则会自动具有拷贝功能。

  • 相关阅读:
    Notes 20180508 : Java基本程序设计结构之关键字与标识符
    Notes 20180507 : Java程序设计之环境搭建与HelloWord
    Notes 20180506 : Java程序设计语言概述
    Knowledge Point 20180506 深究Java的跨平台特性
    Notes 20180505 : 计算机的基础知识
    Notes 20180310 : String第二讲_String的声明与创建
    Notes 20180309 : String第一讲_char的可读序列
    chrome 調試 node 代碼
    mongoose 5.0 链接数据库 代码保存
    koa-compose 类库学习
  • 原文地址:https://www.cnblogs.com/blogtech/p/11149940.html
Copyright © 2020-2023  润新知