设计模式学习总结4 - 创建型4 - Prototype原型模式

Prototype原型模式(创建型)


作用:

原型模式通过克隆已存在的原型类实例新对象。原型模式有两点优势:1、因为复制对象比构造新对象要快,而且这些要复制的对象已加载在内存中,可以快速复制这些大对象来创建新的对象;2、可以保留大对象的固定的部分来复制新对象,简化子类的实例过程。

Role
The  Prototype pattern  creates  new  objects by  cloning one of  a few stored  prototypes. The Prototype pattern has two advantages: it speeds up the instantiation of very large, dynamically loaded classes (when copying objects is faster), and it keeps a record of identifiable parts of a large data structure that can be copied without knowing the subclass from which they were created.

设计:

IPrototype,定义可以被克隆原型接口
Prototype,实现了原型接口,可以克隆出新对象
PrototypeManager,原型管理器,管理各种可克隆类型和他们的关键词
举例:
IPrototype:可复制的功能
Prototype:实现可复制功能的钢笔
PrototypeManager:管理各种具有克隆自己功能的钢笔
实现:

实例1

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PrototypePattern;

namespace Prototype
{
    [Serializable()]
    
// Helper class used to create a second level data structure
    class DeeperData 
    {
         
public string Data {getset;}

         
public DeeperData(string s) 
         {
           Data 
= s;
         }
         
public override string ToString () 
         {
           
return Data;
         }
    }
    


    [Serializable()]
    
class  Prototype : IPrototype <Prototype>  
    {
         
// Content members
         public string Country {getset;}
         
public string Capital {getset;}
         
public DeeperData Language {getset;}

         
public Prototype (string country, string capital, string language) 
         {
           Country 
= country;
           Capital 
= capital;
           Language 
= new DeeperData(language);
         }

         
public override string ToString() 
         {
           
return Country+"\t\t"+Capital+"\t\t->"+Language;
         }
    }
    
class PrototypeManager 
    {
        
public Dictionary <string, Prototype> prototypes
            
= new Dictionary <string, Prototype>
            {
                {
"Germany",
                
new Prototype ("Germany""Berlin""German")},
                {
"Italy",
                
new Prototype ("Italy""Rome""Italian")},
                {
"Australia",
                
new Prototype ("Australia""Canberra""English")}
            };
    }
    
//引用类型
    class RefTypeRectangle
    {
        
public int Width;
        
public int Height;
    }

    
class Program
    {
        
static void Report (string s, Prototype a, Prototype b) {
             Console.WriteLine(
"\n"+s);
             Console.WriteLine(
"Prototype "+a+"\nClone      "+b);
           }

        
static void Main(string[] args)
        {
            
#region 测试引用类型
            
/*
            //有该程序可以看出,引用类型是相互影响的,因为他们是指向相同的内存空间实际的是操作同一个堆栈中的数据
            RefTypeRectangle refOne = new RefTypeRectangle();
            RefTypeRectangle refTwo = refOne;
            refOne.Width = 10;
            refOne.Height = 20;
            System.Console.WriteLine("引用类型测试:");
            System.Console.WriteLine("refTwo.Width:" + refTwo.Width);
            System.Console.WriteLine("refTwo.Height:" + refTwo.Height);
            System.Console.WriteLine("-----------------------------------");
            refTwo.Width = 15;
            refTwo.Height = 25;
            System.Console.WriteLine("refOne.Width:" + refOne.Width);
            System.Console.WriteLine("refOne.Height:" + refOne.Height);
            System.Console.WriteLine("-----------------------------------");



            string s1 = "s1";
            string s2 = s1;
            Console.WriteLine(s1);
            s2 = "s2";
            Console.WriteLine(s1);
            Console.ReadLine();
            
*/
            
#endregion 
           PrototypeManager manager 
= new PrototypeManager();
           Prototype  c2, c3;
  
           
// Make a copy of Australia's data
           c2  =  manager.prototypes["Australia"].Clone();
           Report(
"Shallow cloning Australia\n===============",
               manager.prototypes[
"Australia"], c2);
  
          
// Change the capital of Australia to Sydney
           c2.Capital = "Sydney";
           Report(
"Altered Clone's shallow state, prototype unaffected",
               manager.prototypes[
"Australia"], c2);
  
           
// Change the language of Australia (deep data)
           c2.Language.Data = "Chinese";
           Report(
"Altering Clone deep state: prototype affected *****",
                   manager.prototypes[
"Australia"], c2);
  
           
// Make a copy of Germany's data
           c3  =  manager.prototypes["Germany"].DeepCopy();
           Report(
"Deep cloning Germany\n============",
                   manager.prototypes[
"Germany"], c3);
  
           
// Change the capital of Germany
           c3.Capital = "Munich";
           Report(
"Altering Clone shallow state, prototype unaffected",
                   manager.prototypes[
"Germany"], c3);
  
           
// Change the language of Germany (deep data)
           c3.Language.Data = "Turkish";
           Report(
"Altering Clone deep state, prototype unaffected",
               manager.prototypes[
"Germany"], c3);

           Console.ReadLine();
        }
    }
}

 

 

代码
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace PrototypePattern 
{
    
// Prototype Pattern        Judith Bishop  Nov 2007
    
// Serialization is used for the deep copy option
    
// The type T must be marked with the attribute [Serializable()]

    [Serializable()]
    
public abstract class IPrototype <T> 
    {

         
// Shallow copy
         public T Clone() 
         {
              
return (T) this.MemberwiseClone();
         }

         
//Deep Copy
           public T DeepCopy() 
           {
               MemoryStream stream 
= new MemoryStream();
               BinaryFormatter formatter 
= new BinaryFormatter();
               formatter.Serialize(stream, 
this);
               stream.Seek(
0, SeekOrigin.Begin);
               T copy 
= (T) formatter.Deserialize(stream);
               stream.Close();
               
return copy;
           }
    }
}

 

 

 使用场景:

1、隐藏具体的类,不让客户端知道
2、在运行时通过原型类添加或删除新类
3、在系统中保持最小数量的类
4、适用于在运行时改变数据的结构
5、在C#3.0中使用深度克隆是非常简单的
Use the Prototype pattern when…
You want to:
•  Hide concrete classes from the client.
•  Add and remove new classes (via prototypes) at runtime.
•  Keep the number of classes in the system to a minimum.
•  Adapt to changing structures of data at runtime.

总结:
Prototype原型模式是一种创建型模式,解决“结构复杂对象”的创建工作。《设计模式》:使用原型实例创建指定的对象类型,然后通过拷贝这些原型来创建新的对象。原型模式是通过拷贝一个已存在的实例来创建新的对象,这一点和其他创建型模式不相同。
Prototype原型模式的几个要点:
1、Prototype原型模式隔离对象的使用者和具体类型之间的耦合关系,它同样要求这些要使用的类拥有“稳定的接口”。
2、Prototype原型模式采用克隆原型的方法来创建对象,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方不断地Clone克隆。
3、Prototype模式中的Clone方法可以利用Object类的浅拷贝MemberwiseClone()或者序列化来实现深拷贝DeepCopy()。
这里面我们再来说说浅拷贝和深拷贝。对于Prototype模式是很重要的。浅拷贝和深拷贝的关键区别是对于对象内引用类型数据的拷贝。
public class ClassB
{}
public class MainClass
{
    int a;
    ClassB b;
}

我们用浅拷贝实现了两个对象MainClass1和MainClass2,对于MainClass1.a和MainClass2.a,他们是值类型,在MainClass2.a是新分配的内存,他们所有的内存空间是不一样,值是相等的,但是MainClass1.b和MainClass2.b,由于它们是引用类型,在浅拷贝时只是拷贝了MainClass1.b的地址给MainClass2的b成员,实际上MainClass1.b和MainClass2.b指向同一块内存。
但如果我们用深拷贝,MainClass1.b和MainClass2.b指向的是不同的内存地址。一般利用序列化和反序列化来实现深拷贝来创建新的引用类型。

posted on 2010-03-01 19:37  Utopia Coming  阅读(1195)  评论(0编辑  收藏  举报

导航