一天一个设计模式——Prototype 原型模式

1、模式说明java

   看了比较多的资料,对原型模式写的比较复杂,我的的理解就是模型复制,根据现有的类来直接建立新的类,而不是调用类的构造函数。框架

  那为何不直接调用new方法来建立类的实例呢,主要一个缘由是若是类的构造函数比较复杂,又须要大量的类实例对象,且这些类比较相似的时候,就可使用原型模式,调用对象的克隆方法快读获得实例。另外一个缘由是,使用构造函数建立类时,语句MyClass myInstance = new MyClass();  这个Java语句中,咱们使用了要建立的类的名字:MyClass,如此一来,就讲MyClass类和当前语句所在的类紧密耦合在一块儿了,并且,若是咱们还不知道要建立的类的名字,可是想先定义类的建立方式,就须要使用原型模式。ide

2、原型模式的类图函数

3、原型模式中的角色测试

  • 原型(Protype)角色:负责定义复制现有实例生成新实例的方法
  • 具体原型(ConcretePrototype)角色:负责实现复制现有实例生成新实例的方法
  • 使用者(Client)角色:负责使用复制实例的方法生成新实例

4、代码示例this

1.Product类:spa

package com.designpattern.cn.protptypepattern.patternframework;

public interface Product extends Cloneable {
    public abstract void use(String s);
    public abstract Product createClone();
}
View Code

  上面的Product类很简单,只是继承了java.lang.Clonable接口,该接口中并无要求实现任何方法,这是一个标记接口,被该接口标记的类能够调用Clone方法来克隆类实例。须要注意的是,Clone方法并非定义在Clonable接口中,而是定义在java.lang.Object中,另外须要提一点,Clone方法实现的是浅复制。prototype

2.Manager类:设计

package com.designpattern.cn.protptypepattern.patternframework;

import java.util.HashMap;

public class Manager {
    private HashMap showcase = new HashMap();
    public void register(String name, Product product){
        showcase.put(name, product);
    }
    public Product create(String protoname){
        Product p = (Product) showcase.get(protoname);
        return p.createClone();
    }
}
View Code

  上面的Manager类提供了register方法,将字符串和Product接口注册保存到showcase中,如今还没法知道Product具体类是什么,可是能够肯定这个具体类是实现了Product接口的,所以这个类能够调用use方法和createClone方法建立实例的克隆。3d

  接下来建立几种不一样的Product具体的子类,每一个子类都实现了Product接口:

3-1.MessageBox消息盒子类:

package com.designpattern.cn.protptypepattern.patterndemostrate;

import com.designpattern.cn.protptypepattern.patternframework.Product;

public class MessageBox implements Product {
    private char decochar;
    public MessageBox(char decochar){
        this.decochar = decochar;
    }

    public void use(String s){
        int length = s.getBytes().length;
        for(int i = 0; i < length + 4; i++){
            System.out.print(decochar);
        }
        System.out.println("");
        System.out.println(decochar+" "+s+" "+decochar);
        for(int i = 0; i < length + 4; i++){
            System.out.print(decochar);
        }
        System.out.println("");
    }

    public Product createClone(){
        Product p = null;
        try {
            p = (Product) clone();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return p;
    }
}
View Code

3-2UnderlinePen类:

package com.designpattern.cn.protptypepattern.patterndemostrate;

import com.designpattern.cn.protptypepattern.patternframework.Product;

public class UnderlinePen implements Product {
    private char ulchar;
    public UnderlinePen(char ulchar){
        this.ulchar = ulchar;
    }

    public void use(String s){
        int length = s.getBytes().length;
        System.out.println("\"" + s + "\"");
        System.out.println(" ");
        for(int i = 0; i < length + 4; i++){
            System.out.print(ulchar);
        }
        System.out.println("");
    }

    public Product createClone(){
        Product p = null;
        try {
            p = (Product) clone();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return p;
    }
}
View Code

  从上面两个类能够看出,Manager类的create方法中并无出现MessageBox和UnderlinePen这些字眼,取而代之使用的是本身定义的字符串,并将这个字符串注册到Manager类中,后续根据字符串来获得类实例(经过原型克隆获得)。如此一来,就将框架和具体的类名解耦开了。

 

4.测试类和运行结果:

原型模式在JavaScript中也有应用,后续再补充这方面的内容,能够对比看下Java和Javascript中实现原型模式的不一样。

---------------------2019-06-27 00:13 比较晚了,今天加班到10点回家,原型模式仍是比较重要的,这篇随笔后续继续补充-----------------------------

 

5、JavaScript中的原型模式

  在《Javascript 高级程序设计》一书中,在讲如何在Javascript中建立对象时,是这样介绍原型模式的:prototype是经过调用构造函数而建立的那个对象实例的原型对象。这句话反过来讲:咱们建立的每一个函数都有一个prototype属性,它是一个指针,指向一个对象,这个对象包含了能够由特定类型的全部实例共享的属性和方法。总之:没必要在构造函数中定义对象实例信息,而是将这些信息直接添加到原型对象中。

  举例说明:

  上面代码看出,当建立一个函数时(即便函数没有包含任何内容),就会建立一个prototype属性,该属性指向函数的原型对象,全部的原型对象会有一个constructor属性,该属性是一个指针,指向prototype属性所在的函数的指针。上面的例子:Person.prototype.constructor  指向 Person。

  使用原型对象的好处是:全部原型对象的实例都共享原型的属性和方法。换种说法,没必要在构造函数中定义对象实例的信息,而是将这些对象信息放到原型对象中。

  由此咱们能够想:若是咱们本身建立一个对象,做为另外一个对象的prototype属性值,而后经过Object.create(prototype, optionalDescriptorObjects)来实现原型继承。

  继续完善上面的代码:

  若是咱们要本身实现原型模式:

6、与原型模式相关的模式

  • Flyweight享元模式:Prototype原型模式用于建立与当前实例彻底相同的实例,Flyweight模式能够在不一样的地方使用同一个实例
  • Memento备忘录模式:备忘录模式能够保存当前实例的状态,实现快照和撤销功能
  • Composite组合模式
  • Command命令模式:想要复制命令模式中的命令时,可使用Protype模式。
相关文章
相关标签/搜索