Prototype 原型(创建型模式)

依赖关系的倒置

抽象不应该依赖于实现细节,实现细节应该依赖于抽象。

– 抽象A直接依赖于实现细节b

Prototype 原型(创建型模式)_第1张图片 

 

–抽象A依赖于抽象B,实现细节b依赖于抽象B

Prototype 原型(创建型模式)_第2张图片

 

动机(Motivation)

      在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
      如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象” ,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?

 

意图(Intent)
使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。——《设计模式》GoF

 

结构(Structure)

Prototype 原型(创建型模式)_第3张图片

 

 

  实例代码

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

using  System.IO;
using  System.Runtime.Serialization.Formatters.Binary;

namespace  testWpf
{
    
///   <summary>
    
///  抽象类,虽然没有声明成abstract,或者这里称为高层类,这是为了共享Clone方法
    
///   </summary>
    [Serializable]
    
public   class  NormalActor
    {
        
// 跟.Net的Clone不一样
         public   virtual  NormalActor Clone()
        {
            
/*
             * MemberwiseClone 方法创建一个浅表副本,具体来说就是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。
             * 如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;
             * 因此,原始对象及其复本引用同一对象。
             * 因此这里使用了对象序列化和反序列化的方式得到一个深拷贝对象
             
*/
            MemoryStream stream 
=   new  MemoryStream();
            BinaryFormatter formatter 
=   new  BinaryFormatter(); 
            formatter.Serialize(stream, 
this );
            stream.Position 
=   0 ;
            
return  formatter.Deserialize(stream)  as  NormalActor;
        }
    }

    
///   <summary>
    
///  抽象类,虽然没有声明成abstract,或者这里称为高层类,这是为了共享Clone方法
    
///   </summary>
    [Serializable]
    
public   class  FlyActor
    {
        
// 跟.Net的Clone不一样
         public   virtual  FlyActor Clone()
        {
            MemoryStream stream 
=   new  MemoryStream();
            BinaryFormatter formatter 
=   new  BinaryFormatter();
            formatter.Serialize(stream, 
this );
            stream.Position 
=   0 ;
            
return  formatter.Deserialize(stream)  as  FlyActor;
        }
    }

    
///   <summary>
    
///  抽象类,虽然没有声明成abstract,或者这里称为高层类,这是为了共享Clone方法
    
///   </summary>
    [Serializable]
    
public   class  WaterActor
    {
        
// 跟.Net的Clone不一样
         public   virtual  WaterActor Clone()
        {
            MemoryStream stream 
=   new  MemoryStream();
            BinaryFormatter formatter 
=   new  BinaryFormatter();
            formatter.Serialize(stream, 
this );
            stream.Position 
=   0 ;
            
return  formatter.Deserialize(stream)  as  WaterActor;
        }
    }

    
///   <summary>
    
///  虽然父类NormalActor已经是声明了可序列化标识“[Serializable]”,
    
///  但“[Serializable]”是不可继承的,所以子类如果要可以序列化,则还是要加上[Serializable]标识
    
///   </summary>
    [Serializable]
    
public   class  NormalActorA : NormalActor
    {
    }

    [Serializable]
    
public   class  NormalActorB : NormalActor
    {
    }

    [Serializable]
    
public   class  FlyActorA : FlyActor
    {
       
    }

    [Serializable]
    
public   class  FlyActorB : FlyActor
    {
    }

    [Serializable]
    
public   class  WaterActorA : WaterActor
    {
    }

    [Serializable]
    
public   class  WaterActorB : WaterActor
    {
    }

    
public   class  GameSystem
    {
        
public  NormalActor normalActor;
        
public  FlyActor flyActor;
        
public  WaterActor waterActor; 

        
public   void  Run()
        {
            NormalActor normalActor1 
=  normalActor.Clone();
            NormalActor normalActor2 
=  normalActor.Clone();
            NormalActor normalActor3 
=  normalActor.Clone();
            NormalActor normalActor4 
=  normalActor.Clone();
            NormalActor normalActor5 
=  normalActor.Clone();

            FlyActor flyActor1 
=  flyActor.Clone();
            FlyActor flyActor2 
=  flyActor.Clone();

            WaterActor waterActor1 
=  waterActor.Clone();
            WaterActor waterActor2 
=  waterActor.Clone();
        }
    }

    
public   class  App
    {
        
public   static   void  Main()
        {
            GameSystem gameSystem 
=   new  GameSystem();
            gameSystem.normalActor 
=   new  NormalActorA();
            gameSystem.flyActor 
=   new  FlyActorB();
            gameSystem.waterActor 
=   new  WaterActorA();
            gameSystem.Run();
        }
    }
}

 

 

Prototype模式的几个要点

  1. Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”。
  2. Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方不断地Clone。
  3. Prototype模式中的Clone方法可以利用.NET中的Object类的MemberwiseClone()方法或者序列化来实现深拷贝。

 

有关创建性模式的讨论

  1. Singleton模式解决的是实体对象个数的问题。除了Singleton之外,其他创建型模式解决的都是new所带来的耦合关系。
  2. Factory Method, Abstract Factory, Builder都需要一个额外的工厂类来负责实例化“易变对象”,而Prototype则是通过原型(一个特殊的工厂类)来克隆“易变对象”。
  3. 如果遇到“易变类”,起初的设计通常从FactoryMethod开始,当遇到更多的复杂变化时,再考虑重构为其他三种工厂模式( Abstract Factory,Builder , Prototype )。

最后谈谈使用Prototype模式需要使用到的两个技术问题:MemberwiseClone与Clone,[Serializable]属性能否继承的问题

一、MemberwiseClone与Clone

       MemberwiseClone 方法创建一个浅表副本,具体来说就是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。

下面的代码就是演示这个问题:

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

using  System.IO;
using  System.Runtime.Serialization.Formatters.Binary;

namespace  testWpf
{
    [Serializable]    
    
class  DemoClass    
    {        
        
public   int  i  =   0 ;
        
public   int [] iArr  =  {  1 2 3  };
        
public  DemoClass Clone1()        
        {            
            
return   this .MemberwiseClone()  as  DemoClass;        
        }        
        
        
public  DemoClass Clone2()        
        {           
            MemoryStream stream 
=   new  MemoryStream();
            BinaryFormatter formatter 
=   new  BinaryFormatter();
            formatter.Serialize(stream, 
this );
            stream.Position 
=   0 ;
            
return  formatter.Deserialize(stream)  as  DemoClass;
        }    
    }    
    
class  Program    
    {        
        
static   void  Main( string [] args)
        {            
            DemoClass a 
=   new  DemoClass();
            a.i 
=   10 ;            
            a.iArr 
=   new   int [] {  8 9 10  };
            DemoClass b 
=  a.Clone1();            
            DemoClass c 
=  a.Clone2();             //  更改 a 对象的iArr[0], 导致 b 对象的iArr[0] 也发生了变化              
            a.iArr[ 0 =   88 ;            
            Console.WriteLine(
" MemberwiseClone " );            
            Console.WriteLine(b.i);            
            
foreach  (var item  in  b.iArr)            
            {                
                Console.WriteLine(item);            
            }            
            Console.WriteLine(
" Clone2 " ); 
            Console.WriteLine(c.i);       
            
foreach  (var item  in  c.iArr)    
            {          
                Console.WriteLine(item);
            }        
            Console.ReadLine();  
        }  
    }
}

 

 

 

 二、[Serializable]属性能否继承的问题

代码
    [Serializable]
    
public   abstract   class  CSMessage : MessageBase
    {
        
private   string  userName;
        
protected  CSMessage( string  anUserName)
        {
            userName 
=  anUserName;
        }

        
public   string  UserName
        {
            
get  {  return  userName; }
        }

    }


    [Serializable]
    
public   class  LoginMessage : CSMessage
    {
        
private   string  password;
        
public  LoginMessage( string  userName,  string  password)
            : 
base (userName)
        {
            
this .password  =  password;
        }
        
public   string  Password
        {
            
get  {  return  password; }
        }
    }

 

代码如上,测试发现类属性是不可以继承的,仔细推敲MSDN上关于对类属性是说明,类属性是一种标记当代码被编译为MSIL后由CLR根据类属性标记为其它附上相关的特性,唉。。不仔细看还是很容易弄错的

你可能感兴趣的:(prototype)