第132章(1 / 1)

大话设计模式 吴强 2237 字 2个月前

小A:“克隆对象有哪些?”

大B:“克隆对象分为浅拷贝和深拷贝。我给你详细讲一下。浅拷贝就是克隆的对象和它的源对象共享引用的对象,举个例子,可能不恰当,假设牛肉刀削面引用一个对象:Money,表示它值多少钱,这里说的对象是说它是System.Object继承的(c#),也就是说不同的浅拷贝对象,他们的价钱是一样的,当克隆对象的价钱变过之后,它所引用的对象的价钱也就随之改变了,比如面馆。调低了牛肉刀削面的价格,由5块钱调到了4块钱,那么每碗面的价格都变到了4块钱。但对值类型而言,每个浅拷贝对象都有自己的拷贝,也就是说,当改变克隆对象的值类型时,它的源对象相应属性不会改变。深拷贝就是完全的拷贝。不仅值类型有自己的拷贝,连引用对象也有自己的一份拷贝,修改克隆对象的任何属性,也不会对源对象产生任何影响。原型管理器,就是提供原型注册使用,当创建对象使,可以使用里面的对象进行克隆,当有新的实例对象时,也可以将他们加到原型管理器里。说的有点乱,程序员,还是用代码交流最好。”

下面的程序分别实现了原型克隆时浅拷贝和深拷贝。

//

//理解深拷贝和浅拷贝

//

//浅表副本创建与原始对象具有相同类型的新实例,然后复制原始对象的非静态字段。

//如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制该

//引用但不复制被引用的对象;这样,原始对象中的引用和复本中的引用指向同一个对象。

//相反,对象的深层副本复制对象中字段直接或间接引用的全部内容。

//

//例如,如果X是一个具有对对象A和对象B的引用的Object,并且对象A还具

//有对对象M的引用,则X的浅表副本是对象Y,而Y同样具有对对象A和对象。

//的引用。相反,X的深层副本是对象Y,而对象Y具有对对象C和对象D的直接引

//用以及对对象N的间接引用,其中C是A的副本,D是B的副本,而N是M的副本。

usingSystem;

usingSystem.Collections;

usingSystem.IO;

usingSystem.Runtime.Serialization.Formatters.Binary;

usingSystem.Runtime.Serialization;

usingSystem.Data;

namespacePrototype

{

///《summary》

///Prototype类型实例

///《/summary》

classTestPrototypeApp

{

///《summary》

///应用程序的主入口点。

///《/summary》

[STAThread]

staticvoidMain(string[]args)

{

//定义原型管理器

NoodleManagernoodleManager=newNoodleManager();

//客户要求下面三碗面

NoodlebeefNoodle=(Noodle)noodleManager[“牛肉拉面”].Clone();

//NoodlebeefNoodle=(Noodle)noodleManager[“牛肉拉面”].DeepClone();

NoodlemuttonNoodle=(Noodle)noodleManager[“羊肉拉面”].Clone();

NoodlebeefCutNoodle=(Noodle)noodleManager[“牛肉刀削面”].Clone();

//修改克隆对象中的引用对象的属性,验证它是浅拷贝还是深拷贝

beefNoodle.TbName=,“哈哈哈!克隆对象改名了,你改不改”;

//显示原始对象的NoodelName和TbName?

Console.WriteLine(noodleManager[“牛肉拉面”].NoodleName+noodleManager[“牛肉拉面”].TbName+“\n”);

//显示克隆对象的NoodleName和。

Console.WriteLine(beefNoodle.NoodleName+beefNoodle.TbName+“\n”);

//将新的产品加入原型管理器,以备以后克隆时使用,下面是定义了一种新的面条-羊肉刀削面,

//并把它添加到面条管理器中,如果以后再有客户点这个面,直接克隆即可。

noodleManager[“羊肉刀削面”]=newCutNoodle(“羊肉刀削面”);

//克隆一碗羊肉刀削面

NoodlemuttonCutNoodle=(Noodle)noodleManager[“羊肉刀削面”].Clone();

Console.WriteLine(noodleManager[“羊肉刀削面”].NoodleName+“\n”);

Console.WriteLine(muttonCutNoodle.NoodleName+“\n”);

Console.ReadLine();

}

}

//抽象产品-面条

//序列化属性,为深拷贝时使用,每个派生类都要加上此属性才能实现深拷贝

[Serializable]

publicabstractclassNoodle

{

//定义一个DataTable对象,主要是为了验证对比类中含有引用对象时的深拷贝和浅拷贝时的不同,

//你也可以采用别的任何引用对象

protectedDataTabledataTable=newDataTable();

publicstringTbName

{

get{returndataTable.TableName;}

set{dataTable.TableName=value;}

}

//字段

protectedstringnoodleName;

//特性

publicstringNoodleName

{

get{returnnoodleName;}

set{noodleName=value;}

}

publicabstractNoodleMake(stringname);

//浅克隆的接口

publicabstractNoodleClone();

//深克隆的接口

publicabstractNoodleDeepClone();

}

//具体产品,拉面

[Serializable]

publicclassPullNoodle:Noodle

{

publicPullNoodle(stringname)

{

this.NoodleName=name;

this.TbName=name+“table”;

Console.WriteLine(“PullNoodleismade\n”);

}

//实现浅拷贝

publicoverrideNoodleClone()

{

return(Noodle)this.MemberwiseClone();

}

//实现深拷贝,“淹咸菜”的过程,先将对象序列化到内存流,再反序列化,即可得到深克隆

publicoverrideNoodleDeepClone()

{

//定义内存流

MemoryStreamms=newMemoryStream();

//定义二进制流

IFormatterbf=newBinaryFormatter();

//序列化

bf.Serialize(ms,this);

//重置指针到起始位置,以备反序列化

ms.Position=0;

//返回反序列化的深克隆对象

return(Noodle)bf.Deserialize(ms);

}

publicoverrideNoodleMake(stringname)

{

returnnewPullNoodle(name);

}

}

//具体产品-刀削面

[Serializable]

publicclassCutNoodle:Noodle

{

publicCutNoodle(stringname)

{

this.NoodleName=name;

this.TbName=name+“table”;

Console.WriteLine(“CutNoodleismade\n”);

}

//实现浅克隆

publicoverrideNoodleClone()

{

return(Noodle)this.MemberwiseClone();

}

publicoverrideNoodleMake(stringname)

{

returnnewCutNoodle(name);

}

//实现深克隆

publicoverrideNoodleDeepClone()

{

MemoryStreamms=newMemoryStream();

IFormatterbf=newBinaryFormatter();

bf.Serialize(ms,this);

ms.Position=0;

return(Noodle)bf.Deserialize(ms);

}

}

//定义原型管理器,用于存储原型集合,这里采用的是。

classNoodleManager

{

//定义。

protectedHashtablenoodleHt=newHashtable();

protectedNoodlenoodle;

publicNoodleManager()

{

//初始化时加入三种基本原型

noodle=newPullNoodle(“牛肉拉面”);

noodleHt.Add(“牛肉拉面”,noodle);

noodle=newPullNoodle(“羊肉拉面”);

noodleHt.Add(“羊肉拉面”,noodle);

noodle=newCutNoodle(“牛肉刀削面”);

noodleHt.Add(“牛肉刀削面”,noodle);

}

//索引器,用于添加,访问Noodle对象

publicNoodlethis[stringkey]

{

get{return(Noodle)noodleHt[key];}

set{noodleHt.Add(key,value);}

}

}

}