我读设计模式之原型模式(Prototype Pattern)

     读了这个原型模式,感觉不像是在讲什么模式,倒像是在讲述一种应用,一种关于Clone的应用。
 

     引入     开发过程中,有时候需要创建多个同类型的对象。按照通常的思维,我们只是new多个对象即可。但是如果这个对象的初始化是个耗时的过程,那么多个对象的创建将很难令人接受。

     原型模式的用意是:通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的办法创建出更多的同类型对象。

     C#中可以使用Clone()方法轻松实现对象拷贝,达到原型模式的目的。但是现在涉及一个概念:浅拷贝(shallow copy)深拷贝(deep Copy).区别两种拷贝方式,并实现具体作业,应该是原型模式实现的重点环节。

     
     概念

    (CLR via C#): 浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。而深拷贝是对对象实例中字段引用的对象也进行拷贝的一种方式,所以如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个深拷贝的话,我们将创建一个新的对象和一个新的字符串--新对象将引用新字符串。需要注意的是执行深拷贝后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。

 
     例证

     浅拷贝

     浅拷贝,实现ICloneable接口的Clone方法,使用object对象的MemberwiseClone()方法就可以实现。

namespace Demo1
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            clswork clsA 
= new clswork("1001");
            clsA.setfiled(
"Ivan");
            clsA.setaddress(
"XX");

            clswork clsB 
= clsA.Clone() as clswork;
            clsB.setfiled(
"Yan");
            clsB.setaddress(
"ZZ");

            clsA.display();
            clsB.display();
        }

    }

    
class clswork:ICloneable
    
{
        
private string _id;

        
public string Id
        
{
            
get return _id; }
            
set { _id = value; }
        }

        
private string _name;

        
public string Name
        
{
            
get return _name; }
            
set { _name = value; }
        }


        
private mycls clstest=new mycls();

        
public clswork(string id)
        
{
            
this._id = id;
            
        }

        
public void setaddress(string add)
        
{
            clstest.address 
= add;
        }

        
public void setfiled(string name)
        
{
            
this._name = name;
        }

        
public void display()
        
{
            Console.WriteLine(
"The id is:{0},the name is: {1},the address is: {2}",Id,Name,clstest.address);
        }


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

    }

    
class mycls
    
{
       
public string address = "test";
    }

}

     执行结果:
The id is:1001,the name is: Ivan,the address is: ZZ
The id is:1001,the name is: Yan,the address is: ZZ
Press any key to continue . . .

     可以看到,浅拷贝,对于引用类型的拷贝是无效的,或者说引用类型的数据段不会被拷贝。这样的话,新建立的对象和原型对象中引用类型对象都指向同一个对象,所以新对象的修改,必然影响到原型对象。
     

     要想使新对象和原型对象互不影响,必须使用深拷贝。实现深拷贝必须手动重写Clone方法,可以使用序列化实现。(注意抽象原型对象和具体对象都要标记为可序列化)

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace Demo1
{
    
class App
    
{
        
static void Main()
        
{
            ConcretePrototype c1 
= new ConcretePrototype("1001""ivan");
            c1.SetAdd(
"深圳");
            c1.show();

            ConcretePrototype c2 
= c1.Clone() as ConcretePrototype;
            c2.SetAdd(
"广州");
            c2.show();
        }

    }


    [Serializable]   
//可序列化
    public abstract class Prototype
    
{
        
public abstract Prototype Clone();
    }


    [Serializable] 
//可序列化
    class ConcretePrototype : Prototype
    
{
        
private string id;
        
private string name;

       
private workAdd workadd;

        
public string Id
        
{
            
get return id; }
            
set { id = value; }
        }

        
public string Name
        
{
            
get return name; }
            
set { name = value; }
        }

        
public void SetAdd(string address)
        
{
            workadd.Address 
= address;
        }

        
public ConcretePrototype(string id, string name)
        
{
            
this.id = id;
            
this.name = name;

            workadd 
= new workAdd();
        }


        
public void show()
        
{
            Console.WriteLine(
"id is {0},name is {1},address is {2}", Id, Name, workadd.Address);
        }


        
public override Prototype Clone() //重写Clone方法
        {
            Prototype MyPrototype;

            MemoryStream memoryStream 
= new MemoryStream();

            BinaryFormatter formatter 
= new BinaryFormatter();

            formatter.Serialize(memoryStream, 
this);

            memoryStream.Position 
= 0;

            MyPrototype 
= (Prototype)formatter.Deserialize(memoryStream);

            
return MyPrototype; 
        }

    }


    [Serializable]  
//可序列化
    class workAdd 
    
{
        
private string address;

        
public string Address
        
{
            
get return address; }
            
set { address = value; }
        }


    }

}

id is 1001,name is ivan,address is 深圳
id is 1001,name is ivan,address is 广州
Press any key to continue . . .

     实现深拷贝,还有另外一种做法:

using System;
using System.Collections.Generic;
using System.Text;

namespace Demo1
{
    
class App
    
{
        
static void Main()
        
{
            ConcretePrototype c1 
= new ConcretePrototype("1001""ivan");
            c1.SetAdd(
"henan");
            c1.show();

            ConcretePrototype c2 
= c1.Clone() as ConcretePrototype;
            c2.SetAdd(
"shandong");
            c2.show();
        }

    }


    
public abstract class Prototype
    
{
        
public abstract Prototype Clone();
    }


    
class ConcretePrototype : Prototype
    
{
        
private string id;
        
private string name;

        
private workAdd workadd;

        
public string Id
        
{
            
get return id; }
            
set { id = value; }
        }

        
public string Name
        
{
            
get return name; }
            
set { name = value; }
        }

        
public void SetAdd(string address)
        
{
            workadd.Address 
= address;
        }

        
public ConcretePrototype(string id, string name)
        
{
            
this.id = id;
            
this.name = name;

            workadd 
= new workAdd();
        }

        
public ConcretePrototype(workAdd work)
        
{
            
this.workadd = work.Clone() as workAdd;
        }

        
public void show()
        
{
            Console.WriteLine(
"id is {0},name is {1},address is {2}", Id, Name, workadd.Address);
        }

        
public override Prototype Clone()
        
{
            ConcretePrototype c 
= new ConcretePrototype(workadd);

            c.Id 
= id;
            c.name 
= name;
            
return c;

        }

    }

    
class workAdd : ICloneable
    
{
        
private string address;

        
public string Address
        
{
            
get return address; }
            
set { address = value; }
        }

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

    }

}

     总结     Prototype模式同工厂模式,同样对客户隐藏了对象的创建工作,但是,与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的,达到了“隔离类对象的使用者和具体类型(易变类)之间的耦合关系”的目的。

    

 

     学习参考:

     http://www.cnblogs.com/Ivan-Yan/admin/EditPosts.aspx?opt=1

     http://www.cnblogs.com/zhenyulu/articles/39257.aspx

posted on 2008-07-24 14:36  easy2Dev  阅读(284)  评论(0编辑  收藏  举报

导航