`

原型模式 Prototype Pattern

 
阅读更多

 

一. 原型模式简介
   原型模式(Prototype Pattern)也是一种创建型模式,它关注的是大量相似对象的创建问题。我们经常会遇到这样的情况:在系统中要创建大量的对象,这些对象之间具有几乎完全相同的功能,只是在细节上有一点儿差别。
   这样的情形经常遇到。三国系列游戏是我最喜欢的游戏系列之一。你有没有注意到那里边上百位英雄的头像基本上很相似?你仔细区分就会发现,虽然每个人都不同,但基本上只具有几种脸型:长方的、圆形的、细长的,然后配上不同的胡子、眉毛、眼睛、嘴,有的再加点儿伤疤或装饰物(比如给独眼龙夏侯敦加个单眼罩),就成了不同的人物头像!那么,为什么会这样的?因为根据研究表明,人类的脸谱基本上只有有限的几个类型,只不过在细节和组合方面存在些许差异。游戏制作者具有依据这个理论,只对人脸进行有限的几种建模,然后再通过组合、修饰,就可以产生无数的头像了。
   用面向对象的方法来说就是,我们先建立一个原型,然后通过对原型进行复制和修饰的方法,就可以产生一个和原型相似的新对象。用GoF的话来说就是:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

 

二. 原型模式实例
   前几天,我很 不幸把屋门的钥匙给弄丢了,结果进不了家门。万幸的是,GF那儿还有一把,于是第二天我拿了她的那把去配钥匙。另外,她还让我顺便给她配一把橱柜的钥匙。 现在配个钥匙真是简单,把钥匙给他,他直接找一个合适的钥匙胚子,把我的钥匙夹在配钥匙机的一端,胚子夹在另一端,一开电源,一把标尺比着我的钥匙齿型走 一遍,砂轮就在胚子上复制出一把钥匙来!一分钟不到,两把新钥匙就搞定了!
        用OO来描述,我的    
  旧钥匙是一个原型。配钥匙的过程就是根据我提供的原型,再复制一份出来,就有了一个新的钥匙。两个钥匙完全一样,我也可以给新配的钥匙贴个标签,以表明是“我的”。用这样的方法,我可以对各种钥匙进行复制,也可以复制无限多份。OO分析的类图如下:
                
  程序代码如下:
namespace  Prototype
{
    
// 抽象钥匙原型
     public   abstract   class  Key
    
{
        
private   string  name;
 
        
public   string  Name
        
{
            
get   return  name; }
            
set   { name  =  value; }
        }

        
private   string  owner;
 
        
public   string  Owner
        
{
            
get   return  owner; }
            
set   { owner  =  value; }
        }

        
public  Key( string  name,  string  owner)
        
{
            
this .name  =  name;
            
this .owner  =  owner;
        }

        
// 钥匙复制自身的抽象定义
         public   abstract  Key Clone();
        
public   override  String ToString()
        
{
            
return   this .Name  +   " , belongs to  "   +   this .Owner;
        }

    }

    
// 大门钥匙
     public   class  GateKey : Key
    
{
        
public  GateKey( string  owner) :  base ( " Gate Key " , owner)  { }
 
        
public   override  Key Clone()
        
{
            
return   new  GateKey( this .Owner);
        }

    }

    
// 橱柜钥匙
     public   class  CabinetKey : Key
    
{
        
public  CabinetKey( string  owner) :  base ( " Cabinet Key " , owner)  { }
 
        
public   override  Key Clone()
        
{
            
return   new  CabinetKey( this .Owner);
        }

    }

    
// 客户调用方法
     public   class  Client
    
{
        
public   static   void  Main( string [] args)
        
{
            Key oldGateKey, newGateKey, oldCabinetKey, newCabinetKey;
            oldGateKey 
=   new  GateKey( " GF " );
            newGateKey 
=  oldGateKey.Clone();
            newGateKey.Owner 
=   " Me " ;
            oldCabinetKey 
=   new  CabinetKey( " Me " );
            newCabinetKey 
=  oldCabinetKey.Clone();
            newCabinetKey.Owner 
=   " GF " ;
 
            Console.WriteLine(oldGateKey);
            Console.WriteLine(newGateKey);
            Console.WriteLine(oldCabinetKey);
            Console.WriteLine(newCabinetKey);
        }

    }

}
  这就是原型模式的典型实现:把一个现有对象作为原型,通过对原型进行复制产生新的对象。这样做的好处是:可以通过对原型对象的多次复制,可以产生无限的新对象。

  1. Clone()方法

  原型模式中复制模型对象是通过Clone()方法实现的。其 实,这个方法可以是任意名字,比如CloneKey()、CloneMe()等等。不过,一般应该使用Clone()方法,这样做有两个原因:一是出于习 惯,复制对象当然应该是Clone();二是,在许多语言中的基础类中,比如作为所有类基础的Object,都定义了Clone()方法。因此,实现原型 模式的方法一般应该是:原型类继承了ICloneable接口,在具体原型类中需要时间Clone()方法,完成对象的自我复制。(代码参加下面原型管理 器部分)

  2 . 深复制和浅复制

  复制有两种:深复制和浅复制。浅复制时,复制对象和原型对象共享对象所有的内部变量,两个对象具有一样的内存空间和生命周期。对原型对象的修改同时也修改了它的复制品,反之亦然。
  Object类提供了一个简单的MemberwiseClone()方法来实现浅复制。因为任何一个类的基类都是Object,所以在C#中,实现浅复制非常简单:
 
public   class  GateKey : Key
    
{
        
public  GateKey( string  owner) :  base ( " Gate Key " , owner)  { }

        
public   override  Key Clone()
        
{
            
return  (Key) this .MemberwiseClone();
        }

    }
深复制是指逐个复制原型对象的内部变量,复制对象和原型对象各自具有单独的内存空间和生命周期。复制完成后,他们就是两个完全独立的个体,在逻辑上互不相干。本文实例中的Clone()操作都是深复制的实现。

  3. 原型管理器

  原型对象在原型模式中居于核心的地位。一个系统能产生的对象 的种类多少,取决于系统中存在多少原型。当一个系统中原型对象较多或数量不固定,需要能动态的增加或删除的时候,我们就需要提供一个注册表机制,让客户能 存储、检索和管理可用原型池——这个注册表称为原型管理器。
原型管理器一般是一个关联型存储器,比如哈希表,它包含一些基本操作可以通过关键字来注册、检索、删除原型。具有原型管理器的原型模式如下图所示:
 
  示例代码:
namespace  Prototype
{
    
// 抽象钥匙原型
    [Serializable]
    
public   abstract   class  Key : ICloneable
    
{
        
private   string  name;
 
        
public   string  Name
        
{
            
get   return  name; }
            
set   { name  =  value; }
        }

        
private   string  owner;
 
        
public   string  Owner
        
{
            
get   return  owner; }
            
set   { owner  =  value; }
        }

        
public  Key( string  name,  string  owner)
        
{
            
this .name  =  name;
            
this .owner  =  owner;
        }

 
        
public   override  String ToString()
        
{
            
return   this .Name  +   " , belongs to  "   +   this .Owner;
        }

 
        
public   virtual  Object Clone()
        
{
            MemoryStream memoryStream 
=   new  MemoryStream();
            BinaryFormatter formatter 
=   new  BinaryFormatter();
            formatter.Serialize(memoryStream, 
this );
            memoryStream.Position 
=   0 ;
            
return  formatter.Deserialize(memoryStream);
        }

    }

    
// 大门钥匙
    [Serializable]
    
public   class  GateKey : Key
    
{
        
public  GateKey( string  owner) :  base ( " Gate Key " , owner)  { }
    }

    
// 万能 钥匙 :-)
    [Serializable]
    
public   class  GeneralKey : Key
    
{
        
public  GeneralKey( string  name,  string  owner) :  base (name, owner)  { }
    }

 
    
public   class  KeyManager
    
{
        
private  System.Collections.Hashtable keys  =   new  System.Collections.Hashtable();
 
 
        
public  Key  this [ string  name]
        
{
            
set   { keys.Add(name, value); }
            
get   return  (Key)keys[name]; }
        }

    }

    
// 客户调用方法
     public   class  Client
    
{
        
public   static   void  Main( string [] args)
        
{
            KeyManager keyManager 
=   new  KeyManager();
            keyManager[
" gate " =   new  GateKey( " GF " );
            keyManager[
" key2 " =   new  GeneralKey( " key2 " " GF " );
            keyManager[
" key3 " =   new  GeneralKey( " key3 " " GF " );
            keyManager[
" key4 " =   new  GeneralKey( " key4 " " GF " );
            keyManager[
" key5 " =   new  GeneralKey( " key5 " " GF " );
 
            Key newKey 
=  (Key)keyManager[ " key2 " ].Clone();
            newKey.Name 
=   " Office " ;
            newKey.Owner 
=   " Me " ;
 
            Console.WriteLine(newKey);
        }

    }

}
 
三. 原型模式的结构和角色
  原型模式的一般结构如下:
  • Prototype:抽象原型角色,定义一个原型的抽象定义,其中包含一个复制自身的接口。
  • ConcretePrototypeA/B:具体原型角色,作为原型被复制的具体对象,需实现抽象原型所定义的接口。
  • Client:客户调用端,客户使用原型对象复制出需要的对象
  包含原型管理器的原型模式的结构如下:
  • PrototypeManager:原型管理器角色,提供具体原型对象的增加、删除、浏览等管理功能。
四. 原型模式总结
  原型模式应用于希望系统独立于产品的创建、表示和构成时,这 和工厂模式很类似。事实上,和工厂模式相同的是,原型模式同样对客户隐藏了对象的创建工作,但是,与工厂模式通过对一个类进行实例化来构造新对象不同的 是,原型模式是通过拷贝一个现有对象生成新对象的。工厂模式适用于产品种类有限的情况下,当产品数量巨大或需要提供动态产品增删等性能时,使用原型模式具 有更强的适应性。
  原型模式适用于以下情况(GoF):
  • 当要实例化的类是在运行时刻指定时,例如,通过动态装载;
  • 为了避免创建一个与产品类层次平行的工厂类层次时;
  • 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
分享到:
评论

相关推荐

    Prototype Pattern原型模式

    **原型模式(Prototype Pattern)**是一种基于克隆的创建型设计模式,它的主要目的是为了提高创建新对象的效率,特别是当创建新对象的过程复杂或者资源消耗较大时。在原型模式中,一个已经创建的对象(称为原型)被...

    c++-设计模式之原型模式(Prototype Pattern)

    原型模式(Prototype Pattern)是一种创建型设计模式,允许通过复制现有对象来创建新对象,而不是通过类构造器。这种模式常用于需要频繁创建相似对象的场景,能够提高性能并减少内存使用。 原型模式的组成 原型接口...

    创建型模式之原型模式(Prototype Pattern)

    **原型模式(Prototype Pattern)详解** 在软件设计中,原型模式是一种创建型设计模式,它提供了一种通过复制已有对象来创建新对象的方式,避免了重复的构造过程,提高了代码的效率和可维护性。原型模式的核心思想...

    通过python实现原型模式(Prototype Pattern).rar

    原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象来创建新的对象,而不是通过传统的构造函数或类来实例化对象。原型模式在需要创建大量相似对象且创建过程较为耗时或复杂时非常有用。 在...

    [创建型模式]设计模之原型模式(Prototype Pattern)

    **原型模式(Prototype Pattern)**是一种创建型设计模式,它允许我们通过复制现有的对象来创建新对象,而不是通过构造函数或工厂方法。这种模式的核心在于,它提供了一种更高效、更灵活的方式来创建新实例,特别是在...

    原型设计模式prototype

    **原型设计模式(Prototype Pattern)**是一种创建型设计模式,它允许我们通过复制现有的对象来创建新对象,而不是通过构造函数来实例化新对象。在面向对象编程中,当我们需要频繁地创建具有相同或相似属性的对象时,...

    原型模式(Prototype Pattern)原理图

    原型模式是一种创建型设计模式,它通过复制一个现有的对象来创建新的对象,而不是通过调用构造函数的方式。这种方式可以在运行时动态地创建和修改对象,而不需要知道具体的创建细节 。 原型模式的基本概念包括以下...

    通过java实现原型模式(Prototype Pattern).rar

    在Java中,原型模式通常通过实现一个原型接口或抽象类,并在具体类中提供克隆方法来实现。Java中有一个内置的Cloneable接口和Object类的clone()方法,它们可以被用来实现对象的克隆。但是,直接使用clone()方法需要...

    通过C++实现原型模式(Prototype Pattern).rar

    在C++中,原型模式可以通过定义一个抽象基类(或接口),并在其中声明一个纯虚克隆方法来实现。然后,具体类将继承这个基类并实现克隆方法。由于C++没有内置的克隆机制像Java的Cloneable接口那样,因此我们需要手动...

    Prototype模式

    **原型模式(Prototype Pattern)**是一种创建型设计模式,它提供了一种通过复制已有对象来创建新对象的方式,而不是通过构造函数。在某些情况下,当创建新对象的成本非常高时(例如,对象需要大量的初始化操作或者从...

    .NET设计模式(6):原型模式(PrototypePattern)

    ### .NET设计模式(6):原型模式(Prototype Pattern) #### 概述 在软件工程领域,设计模式提供了一系列经过验证的解决方案,帮助开发者解决常见的软件设计问题。本篇文章聚焦于.NET框架下的“原型模式”...

    C#版 24种设计模式

    适配器模式(Adapter Pattern) 提供者模式(Provider Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 原型模式(Prototype Pattern) 责任链模式(Chain of Responsibility Pattern) 中介者模式...

    用Java实现23种设计模式

    原型模式(Prototype Pattern) 2. 结构型模式 适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern) 过滤器模式(Filter、Criteria Pattern) 组合模式(Composite Pattern) 装饰器模式(Decorator ...

    设计模式之原型模式Java实现和类设计图

    原型模式(Prototype Pattern)是其中一种行为设计模式,主要用于对象创建。它通过复制已有对象来创建新对象,而不是通过传统的构造函数来创建。在Java中,原型模式可以有效地提高性能,特别是在创建复杂对象时。 #...

    设计模式之原型模式

    **原型模式(Prototype Pattern)**是软件设计模式中的结构型模式之一,主要用来简化实例化过程,减少类的创建。在原型模式中,一个对象可以被用作创建其他新对象的模板,通过复制已有对象来创建新对象,而不是通过new...

    C++设计模式(Design Pattern)范例源代码

    原型模式(Prototype) 单件模式(Singleton) 结构型: 适配器模式(Adapter) 桥接模式(Bridge) 组合模式(Composite) 装饰者模式(Decorator) 外观模式(Facade) 蝇量模式(Flyweight) 代理模式(Proxy) 行为型: 责任链...

    常见设计模式的解读和对应代码示例,包括设计原则和软件工程中类之间的依赖关系

    原型模式(Prototype Pattern) 结构型模式(Structural Pattern) 适配器模式(Adapter/Wrapper Pattern) 桥接模式(Bridge Pattern) 装饰模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern)

    设计模式的原型模式的例子

    原型模式(Prototype Pattern)是软件设计模式中的一种结构型模式,它的主要目的是通过复制已有对象来创建新对象,从而减少创建新对象的成本。在原型模式中,类的实例化过程被替换为对已有实例的克隆操作,尤其适用...

    iOS设计模式之原型模式

    本文将深入探讨一种常见的设计模式——原型模式(Prototype Pattern),并结合具体的iOS应用场景进行解析。 原型模式是一种创建型设计模式,它的主要思想是通过复制已有对象来创建新对象,而不是通过构造函数来创建...

Global site tag (gtag.js) - Google Analytics