首页 > 程序开发 > 软件开发 > 其他 >

原型模式 对象创建型模式

2017-04-12

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

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

可以使用原型管理器来管理需要克隆的对象
和其他创建型模式一样都是把产品的创建过程进行封装
原型管理器去掉抽象工厂模式或则工厂方法模式中繁多的子类采用Java的反射机制完成对象的复制,可以说原型模式是在工厂模式的基础上加上了克隆方法。

适用性

当一个系统应该独立于它的产品创建、构成和表示时,要使用Prototype模式;以及
1. 当要实例化的类是在运行时刻指定时,例如,通过动态装载;或者
2. 为了避免创建一个与产品类层次平行的工厂类层次时;或者
3. 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更加方便一些。
4. 在一个复制的类层次中,当系统必须从其中的许多类型创建新对象时,可以考虑原型模式。
5. 种类太多,无法整合成类时
6. 不容易利用类产生对象实例时
7. 希望把框架和所产生的对象实例分开时

参与者

Prototype

声明一个克隆自身的接口 实现自己的clone方法,扮演这种角色的类通常是抽象类,且它具有许多具体子类(Java 中的Object)

ConcretePrototype

实现一个克隆机身的接口 被复制的对象,为抽象原型角色的具体子类

Client

让一个原型克隆自身从而创建一个新的对象

代码

Prototype

public  class Prototype implements Cloneable{
    protected Object clone(){
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

ConcretePrototype

public class ConcretePrototype extends Prototype{
    protected Object clone() {
        return  super.clone();
    }
}

PrototypeManager

public class PrototypeManager {
    private static final PrototypeManager PROTOTYPE_MANAGER = new PrototypeManager();
    private static final Map mapPrototypeCache = new HashMap();
    private PrototypeManager(){}
    public static PrototypeManager getPrototypeManagerInstance(){return PROTOTYPE_MANAGER;} 
    public static void register(String prototypeClassName,Prototype prototype){
        mapPrototypeCache.put(prototypeClassName, prototype);
    }
    public static void remove(String prototypeName){
        mapPrototypeCache.remove(prototypeName);
    }
    public Prototype getPrototype(String prototypeClassName){
        if(mapPrototypeCache.containsKey(prototypeClassName)){
            return (Prototype) mapPrototypeCache.get(prototypeClassName).clone();
        }else{
            Prototype prototype = null;
            try {
                prototype = (Prototype) Class.forName(prototypeClassName).newInstance();
                register(prototypeClassName,prototype);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return prototype;
        }
    }
}

Client

public class Client {
    private String prototypeClassName;
    public Client(String prototypeClassName){
        this.prototypeClassName = prototypeClassName;
    }
    public void operation(){
        Prototype prototype = PrototypeManager.getPrototypeManagerInstance().
                getPrototype(prototypeClassName);
        System.out.println("完成克隆"+prototype);
    }
}

协作

客户请求一个原型克隆自身。

效果

Prototype有许多和Abstract Factory和Builder一样的效果;它对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目。此外,这些模式使客户无需改变即可使用与特定应用相关的类。

优点

向客户隐藏制造新实例的复杂性 提供让客户能够产生未知类型对象的选项 在某些环境下,复制对象比新建对象更有效
运行时刻增加和删除产品

Prototype允许只通过客户注册原型实例就可以将一个新的具体产品类并入系统。它从其他创建型模式更为灵活,因为客户可以在运行时刻建立和删除原型。

改变值以指定新对象

高度动态的系统允许你通过对象复合定义新的行为,例如,通过为一个对象变量指定值,并且不定义新的类。你通过实例化已有类并且将这些实例注册为客户对象的原型,就可以有效定义新类别的对象。客户可以将职责代理给原型,从而表现出新的行为。
这种设计使得用户无需编程即可定义新“类”。实际上,克隆一个原型类似于实例化一个类。Prototype模式可以极大的减少系统所需要的类的数目。

改变结果以指定新对象

许多应用由部件和子部件来创建对象。为方便起见,这样的应用通常允许你实例化复杂的、用户定义的结构。
Prototype模式也支持这一点。使用deep copy实现。

减少子类的构造

Factory Method经常产生一个与产品类层次平行的Creator类层次。Prototype模式使得你克隆一个原型而不是请求一个工厂方法去产生一个新的对象。因此你根本不需要Creator类层次。

用类动态配置应用

一些运行时刻环境运行你动态将类装载到应用中。在像C++这样的语言中,Prototype模式是利用这种功能的关键。
一个希望创建动态载入类的实例的应用不能静态引用类的构造器。而应该由运行环境在载入时自动创建每个类的实例,并用原型管理器来注册这个实例。这样应用就可以向原型管理器请求新装载的类的实例,这些类原本并没有和程序相连接。

缺点

复制对象有时相当复杂
Prototype的主要缺陷是每一个Prototype的子类都必须实现Clone操作,这可能很困难。例如,当所考虑的类已经存在时就难以新增Clone操作。当内部包括一些不支持拷贝或者有循环引用的对象时,实现克隆可能也会很困难。

实现

使用一个原型管理器

当一个系统中原型数目不固定时(也就是说,它们可以动态创建和销毁),要想保持一个可用原型的注册表。客户不会自己来管理原型,但会在注册表中存储和检索原型。客户在克隆一个原型前会向注册表请求该原型。我们称这个注册表为原型管理器。
原型管理器是一个关联存储器,它返回一个与给定关键字相匹配的原型。它有一些操作可以用来通过关键字注册原型和解除注册。客户可以在运行时更改或者浏览注册表。这使得客户无需编写代码就可以扩展并得到系统清单。

实现克隆操作

Prototype模式最困难的部分在于正确实现Clone操作。当对象结构包含循环引用时,这尤为棘手。浅拷贝和深拷贝。
如果系统中的对象提供了Save和Load操作,那么你只需通过保存对象和立刻载入对象,就可以为Clone操作提供一个缺省实现。Save操作将该对象保存在内存缓冲区中,而Load则通过从缓冲区中重构这个对象来创建一个复本。

初始化克隆对象

当一些客户对克隆对象已经相当满意时,另一些客户将会希望使用它们所选择的一些值来初始化该对象的一些或是所有的内部状态。一般来说不可能在Clone操作中传递这些值,因为这些值的数目由于原型的类的不同而会不同。一些原型可能需要多个初始化参数,另一些可能什么也不需要。在Clone操作中传递参数会破坏克隆接口的统一性。
可能会这样,原型的类已经为(重)设定一些关键的状态值定义好了操作。如果这样的话,客户在克隆后马上就可以使用这些操作。否则,你就可能不得不引入一个Initialize操作,该操作使用初始化参数并根据此设定克隆对象的内部状态。注意深拷贝Clone操作,一些复制在你重新初始化他们之前可能必须要被删除掉(删除可以显示地做也可以在Initialize内部做)。

经典例子

克隆、序列化

相关模式

Prototype和Abstract Factory模式在某种方面是相互竞争的。但是它们也可以一起使用。 Abstract Factory可以存储一个被克隆的原型的集合,并且返回产品对象。大量使用Composite和Decorator模式的设计通常也可从Prototype模式处获益。

Flyweight Pattern

原型模式是创建一个跟目前对象系统状态的新对象实例,再加以应用;享元模式则是在不同位置共享同一个对象实例。

Memento Pattern

原始模式创建一个与对象完全一个新对象;Memento Pattern则是存储目前对象实例的状态,才能进行snapshot(快照)和undo(回复)。

Composite 和Decorator Pattern

大量使用组合和装饰模式时,需要能机动创建一些构造复杂的对象实例,此时使用原始模式更方便。

Command Pattern

如果想复制命令模式中的命令时,可能会用到原型模式。

敬请期待“创建型模式总结”。

相关文章
最新文章
热点推荐