设计模式学习笔记之 Prototype 

     Prototype模式是用来创建一系列结构复杂的对象,这些对象经常发生变化,但是却有比较稳定的接口。Prototype模式指定创建类型的种类,通过克隆方法创建原型的新实例。

    public abstract class Viewer
    
{
        
public abstract int IntToView
        
{
            
get;
            
set;
        }

        
public Viewer Clone()
       
{
            
return (Viewer)this.MemberwiseClone();
        }

        
public abstract void ViewData();
    }

     这里定义了一个Viewer抽象类,其中属性IntToView内容是易变的,Clone方法使用的是object. MemberwiseClone(),这是一个浅表克隆,返回值为object型,再将其类型转换为Viewer。object. MemberwiseClone()不能应用于引用类型数据,它只是将源对象的内存地址里的内容都拷贝出来,如果对象只包含值类型则没有问题,若包含引用类型,例如数组,那么新对象和源对象都会指向同一个内存地址,不符合Prototype模式的要求了。

    这里我们可以应用序列化的方式来实现深拷贝,修改如下:

[Serializable]
public abstract class Viewer
{
        
public abstract int IntToView
        
{
            
get;
            
set;
        }

        
public abstract void ViewData();
        
public Viewer Clone()
        
{
            MemoryStream stream 
= new MemoryStream();
            BinaryFormatter formatter 
= new BinaryFormatter();
            formatter.Serialize(stream, 
this);
            stream.Position 
= 0;
            
return (Viewer)formatter.Deserialize(stream);
        }

}

     这样就实现了深拷贝,源对象与新对象不会有任何交集了。

     现在我们具体实现一个Viewer,它仍需要可序列化

[Serializable]
public class MyViewer : Viewer
{
        
private int intToView;
        
public override int IntToView
        
{
            
get
            
{
                
return intToView;
            }

            
set
            
{
                intToView 
= value;
            }

        }

        
public override void ViewData()
        
{
            Console.WriteLine(intToView.ToString());
        }

}

     因为Clone方法在基类中已经写好了,在MyView中不需要修改,只需要重写虚属性和方法。

     在需要创建新对象的时候:

public class MyManager
{
        
public void Run(Viewer viewer)
        
{
            Viewer viewer1 
= viewer.Clone();
            viewer1.IntToView 
= 1;
            Viewer viewer2 
= viewer.Clone();
            viewer2.IntToView 
= 2;
            viewer1.ViewData();
            viewer2.ViewData();
        }

}

     viewer1和viewer2都是通过对参数viewer的克隆来初始化的。如果单从效果上看的话, viewer.Clone()就好像是new了一个同传入参数viewer相同的类型,实际上是复制了viewer的所有数据成员。就这样的好处就在于它们可以被非常灵活的动态初始化,随时都可以创建和销毁。它们的类型可以随着viewer的类型改变而改变,例如Run(new MyViewer()),那么viewer1和viewer2的数据成员就是同MyViewer相同的。另外Prototype模型不需要factory类,使得模型的结构更为简化。

     Clone方法是局限Prototype模式的一个问题。实现对于复杂对象的克隆是比较困难的。

     另外,突然想到对于Singleton类除了声明不可继承外,还应当声明[NonSerializable]来防止被深克隆。

参考: MSDNWebCast C#设计模式纵横谈    李建忠

     回到目录

posted on 2006-09-10 16:47  aiya  阅读(263)  评论(0)    收藏  举报