原型模式

概念: 是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的原型。

原型模式的拷贝:分为"浅拷贝"和"深拷贝"。(这个和我们理解的拷贝是一样的)

浅拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象.
深拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制.

组成

原型模式涉及到三个角色:

(1)客户(Client)角色:客户类提出创建对象的请求。
(2)抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。
(3)具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

用Uml图表示就是:

那么根据上面的描述,我们通过代码来加深理解。首先我们需要创建三个角色,分别是上面的抽象原型,具体原型,客户。

抽象原型:

public interface Prototype{
    /**
     * 克隆自身的对象
     */
    public Object clone();
}

具体原型:

public class ConcretePrototype1 implements Prototype {
    public Prototype clone(){
        //最简单的克隆,新建一个自身对象,没有属性
        Prototype prototype = new ConcretePrototype1();
        return prototype;
    }
}

客户端:

public class Client {

    private Prototype prototype;

    public Client(Prototype prototype){
        this.prototype = prototype;
    }
    public void operation(Prototype example){
        //需要创建原型接口的对象
        Prototype copyPrototype = prototype.clone();
    }
}

这是最简单的克隆方式,被拷贝的对象没有任何的属性。

下面看一下登记形式的原型模式,它多了一个原型管理器(PrototypeManager)角色,该角色的作用是:创建具体原型类的对象,并记录每一个被创建的对象。

登记形式的原型模式

来看代码实现上有什么不同,

抽象原型角色:

public interface Prototype{
    public Prototype clone();
    public String getName();
    public void setName(String name);
}

具体原型角色:

public class ConcretePrototype1 implements Prototype {
    private String name;
    public Prototype clone(){
        ConcretePrototype1 prototype = new ConcretePrototype1();
        prototype.setName(this.name);
        return prototype;
    }
    public String toString(){
        return "Now in Prototype1 , name = " + this.name;
    }
    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }
}
public class ConcretePrototype2 implements Prototype {
    private String name;
    public Prototype clone(){
        ConcretePrototype2 prototype = new ConcretePrototype2();
        prototype.setName(this.name);
        return prototype;
    }
    public String toString(){
        return "Now in Prototype2 , name = " + this.name;
    }
    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }
}

原型管理器角色保持一个聚集,作为对所有原型对象的登记,这个角色提供必要的方法,供外界增加新的原型对象和取得已经登记过的原型对象。

public class PrototypeManager {
    /**
     * 用来记录原型的编号和原型实例的对应关系
     */
    private static Map<String,Prototype> map = new HashMap<String,Prototype>();

    private PrototypeManager(){}
    /**
     * 向原型管理器里面添加或是修改某个原型注册
     */
    public synchronized static void setPrototype(String prototypeId , Prototype prototype){
        map.put(prototypeId, prototype);
    }
    /**
     * 从原型管理器里面删除某个原型注册
     */
    public synchronized static void removePrototype(String prototypeId){
        map.remove(prototypeId);
    }
    /**
     * 获取某个原型编号对应的原型实例
     */
    public synchronized static Prototype getPrototype(String prototypeId) throws Exception{
        Prototype prototype = map.get(prototypeId);
        if(prototype == null){
            throw new Exception("您希望获取的原型还没有注册或已被销毁");
        }
        return prototype;
    }
}

客户端测试:

public class Client {
    public static void main(String[]args){
        try{
            Prototype p1 = new ConcretePrototype();
            PrototypeManager.setPrototype("p1", p1);
            //获取原型来创建对象
            Prototype p3 = PrototypeManager.getPrototype("p1").clone();
            p3.setName("张三");
            System.out.println("第一个实例:" + p3);
            //有人动态的切换了实现
            Prototype p2 = new ConcretePrototype2();
            PrototypeManager.setPrototype("p1", p2);
            //重新获取原型来创建对象
            Prototype p4 = PrototypeManager.getPrototype("p1").clone();
            p4.setName("李四");
            System.out.println("第二个实例:" + p4);
            //有人注销了这个原型
            PrototypeManager.removePrototype("p1");
            //再次获取原型来创建对象
            Prototype p5 = PrototypeManager.getPrototype("p1").clone();
            p5.setName("王五");
            System.out.println("第三个实例:" + p5);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

总结

     如果需要创建的原型对象数目较少而且比较固定的话,可以采取第一种形式。在这种情况下,原型对象的引用可以由客户端自己保存。
  如果要创建的原型对象数目不固定的话,可以采取第二种形式。在这种情况下,客户端不保存对原型对象的引用,这个任务被交给管理员对象。在复制一个原型对象之前,客户端可以查看管理员对象是否已经有一个满足要求的原型对象。如果有,可以直接从管理员类取得这个对象引用;如果没有,客户端就需要自行复制此原型对象。

时间: 2024-08-01 00:37:57

原型模式的相关文章

设计模式之原型模式

一.引入 小菜的问题:要把简历发到多家公司,简历的份数就必须足够. 大鸟的回答:用编程来复制自己简历. 二.解决过程 ① 最初的写法:  简历类: <span style="font-family:KaiTi_GB2312;font-size:24px;">class Resume { private string name; private string sex; private string age; private string timeArea; private s

JavaScript设计模式系列之原型模式

prototype模式通过实例对象指定需要创建的类型,这与factory method模式有本质不同,factory method模式是通过类的继承定义不同子类来达到创建不同类型对象的目的,属于类模式,prototype模式通过调用组合的对象成员生成不同类型的对象实例,属于对象模式. 由于这个特性,prototype具有以下适用场合: · 需要运行时确定实例化的类时,比如动态装载库时 · 避免创建过多子类时.子类太多永远是不受欢迎的,在factory method中我们也提到通过模板或者参数化来

javascript创建对象之原型模式(三)

先上代码: function Human() { }         Human.prototype.name = "成吉思汗";         Human.prototype.sex = "男";         Human.prototype.say = function () {             alert(this.name);         }         var man = new Human();         man.say();

javascript创建对象之函数构造模式和原型模式结合使用(四)

创建自定义类型的常见方式就是组合使用构造函数模式与原型模式一起使用. 构造函数模式用于定义实例对象的特有的部分(属性和方法),原型模式用于定义共享的部分. 这样最大限度的节省了内存的开销. function Human(name, sex) {             this.name = name;             this.sex = sex;             this.getWife=function(){//娶老婆                 if (this.se

javascript创建对象之动态原型模式(五)

动态原型模式是将所有的信息都封装到工造函数中,而构造函数中初始化原型,有保持了同时在使用构造函数和原型的优点. function Human(name, sex) {             this.name = name;             this.sex = sex;             if (typeof this.say != "function") {                 Human.prototype.say = function () {   

Javascript实例教程:使用动态原型模式

文章简介:使用动态原型模式时,不能使用对象字面量重写原型.前面已经解释过了,如果在已经创建了实例的情况系重写原型,那么就会切断现有实例与新原型之间的联系. 有其它OO语言经验的开发人员在看到独立的构造函数和原型时,很可能会感到非常的困惑.动态原型模式正是致力于解决这个问题的一个方案,它把所有信息都封装在了构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点.换句话说,可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型.来看一个例子: f

Javascript教程:组合使用构造函数模式和原型模式

文章简介:创建自定义类型的常见方式,就是组合使用构造函数模式与原型模式.构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性.结果,每个实例都会有自己的一份实例属性的副本.但同时又共享着对方法的引用,最大限度的节省了内存.另外这种模式还支持向构造函 创建自定义类型的常见方式,就是组合使用构造函数模式与原型模式.构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性.结果,每个实例都会有自己的一份实例属性的副本.但同时又共享着对方法的引用,最大限度的节省了内存.另外这种模式还

java设计模式---prototype(原型)模式

设计 java设计模式---prototype(原型)模式 定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.      Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,      工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求      原型对象拷贝它们自己来实施创建.      适用性:当要实例化的类是在运行时刻指定时,例如,通过动态装载:或者  为了避免创建一个与产品类层次平行的工厂类层

php设计模式 Prototype (原型模式)代码

复制代码 代码如下:<?php /** * 原型模式 * * 用原型实例指定创建对象的种类.并且通过拷贝这个原型来创建新的对象 * */ abstract class Prototype { private $_id = null; public function __construct($id) { $this->_id = $id; } public function getID() { return $this->_id; } public function __clone() /

一番话--原型模式

今天来晚了,因为公司周一很多事情要做,而我昨天晚上没有睡好,来了以后什么事情没做先睡了一个上午.:(幸好老板在开会hiahia.不过下次就没有这么幸运了,要是有孙猴子的分身法,随便克隆一个我放在那里干活儿,我睡觉多好呀....所以今天就介绍一下原型模式(prototype)有时候,我们所要创建的对象大致上都很相似,只是在部分属性的值上有所区别,而且,他们的初始化过程相对来说比较复杂,需要耗费一定的时间,那么我们可以使用原型模式.首先初始化一个一个类的一个实例,然后其他的实例通过对第一个实例的克隆