?????? Singleton 單件模式解決的問題是:實體對象個數問題(這個現在還不太容易混)
?????? AbstractFactory 抽象工廠模式解決的問題是:“一系列互相依賴的對象”的創建工作
?????? Builder
生成器模式解決的問題是:“一些復雜對象”的創建工作,
子對象變化較頻繁,對算法相對穩定
????? FactoryMethor
工廠方法模式解決的問題是:某個對象的創建工作
?????
再回來看看今天的
Prototype
原型模式,它是用來解決“某些結構復雜的對象”的創建工作。現在看看,好象還是差不多。這個問題先放在這,我們先往下看
Prototype
原型模式。
?????
《設計模式》中說道:使用原型實例指定創建對象的種類,然后通過拷貝這些原型來創建新的對象。
?????
此時注意:原型模式是通過拷貝自身來創建新的對象,這一點和其他創建型模式不相同。好,我們再來看看原型模式的結構
??????
這個結構說明原型模式的客戶端程序(
ClientApp
)是依賴于抽象(
Prototype
),而對象的具體實現也是依賴于抽象(
Prototype
)。符合設計模式原則中的依賴倒置原則——抽象不應依賴于具體實現,具體實現應依賴于抽象。
?????? 我們現在回來看看原型模式的實現,我定義了一個場景,一個人開這一輛車在一條公路上。現在這件事是確定的,但不確定的有幾點: 1 、人:姓名,性別,年齡; 2 車:什么牌子的; 3 公路:公路名字,長度,類型(柏油還是土路)。現在我們一個個實現。
?????? 先來實現人,定義一個抽象類, AbstractDriver ,具體實現男性( Man )和女性( Women )
public
abstract
class AbstractDriver
??? {
???????
public AbstractDriver()
??????? {
???????????
//
???????????
// TODO:
在此處添加構造函數邏輯
???????????
//
??????? }
???????
public
string name;
???????
public
string sex;
???????
public
int age;
???????
public
abstract
string drive();
???????
public
abstract AbstractDriver Clone();
??? }
???
public
class Man:AbstractDriver
??? {
???????
public Man(string strName,int intAge)
??????? {
??????????? sex = "Male";
??????????? name = strName;
??????????? age = intAge;
??????? }
???????
public
override
string drive()
??????? {
???????????
return name + " is drive";
??????? }
???????
public
override AbstractDriver Clone()
??????? {
???????????
return (AbstractDriver)this.MemberwiseClone();
??????? }
??? }
???
public
class Women:AbstractDriver
??? {
???????
public Women(string strName,int intAge)
??????? {
??????????? sex = "Female";
??????????? name = strName;
??????????? age = intAge;
??????? }
???????
public
override
string drive()
??????? {
???????????
return name + " is drive";
??????? }
???????
public
override AbstractDriver Clone()
??????? {
???????????
return (AbstractDriver)this.MemberwiseClone();
??????? }
??? }
???
注意:抽象代碼中有一個Clone的方法,個人認為這個方法是原型模式的一個基礎,因為前面講了
原型模式是通過拷貝自身來創建新的對象。
?????
下面我們再來實現公路和汽車
?????
公路:
public
abstract
class AbstractRoad
??? {
???????
public AbstractRoad()
??????? {
???????????
//
???????????
// TODO:
在此處添加構造函數邏輯
???????????
//
??????? }
???????
public
string Type;
???????
public
string RoadName;
???????
public
int RoadLong;
???????
public
abstract AbstractRoad Clone();
??? }
???
public
class Bituminous:AbstractRoad??? //
柏油路
??? {
???????
public Bituminous(string strName,int intLong)
??????? {
??????????? RoadName = strName;
??????????? RoadLong = intLong;
??????????? Type = "Bituminous";
??????? }
???????
public
override AbstractRoad Clone()
??????? {
???????????
return (AbstractRoad)this.MemberwiseClone();
??????? }
??? }
???
public
class Cement:AbstractRoad??????? //
水泥路
??? {
???????
public Cement(string strName,int intLong)
??????? {
??????????? RoadName = strName;
??????????? RoadLong = intLong;
??????????? Type = "Cement";
??????? }
???????
public
override AbstractRoad Clone()
??????? {
???????????
return (AbstractRoad)this.MemberwiseClone();
??????? }
??? }
???
???
汽車:
???
public
abstract
class AbstractCar
??? {
???????
public AbstractCar()
??????? {
???????????
//
???????????
// TODO:
在此處添加構造函數邏輯
???????????
//
??????? }
???????
public
string OilBox;
???????
public
string Wheel;
???????
public
string Body;
???????
public
abstract
string Run();
???????
public
abstract
string Stop();
???????
public
abstract AbstractCar Clone();
??? }
???
public
class BMWCar:AbstractCar
??? {
???????
public BMWCar()
??????? {
??????????? OilBox = "BMW's OilBox";
??????????? Wheel = "BMW's Wheel";
??????????? Body = "BMW's body";
??????? }
???????
public
override
string Run()
??????? {
???????????
return
"BMW is running";
??????? }
???????
public
override
string Stop()
??????? {
???????????
return
"BMW is stoped";
??????? }
???????
public
override AbstractCar Clone()
??????? {
???????????
return (AbstractCar)this.MemberwiseClone();
??????? }
??? }
???
public
class BORACar:AbstractCar
??? {
???????
public BORACar()
??????? {
???
??????? OilBox = "BORA's OilBox";
??????????? Wheel = "BORA's Wheel";
??????????? Body = "BORA's Body";
??????? }
???????
public
override
string Run()
??????? {
???????????
return
"BORA is running";
??????? }
???????
public
override
string Stop()
??????? {
???????????
return
"BORA is stoped";
??????? }
???????
public
override AbstractCar Clone()
??????? {
???????????
return (AbstractCar)this.MemberwiseClone();
??????? }
??? }
???
public
class VolvoCar:AbstractCar
??? {
???????
public VolvoCar()
??????? {
??????????? OilBox = "Volvo's OilBox";
??????????? Wheel = "Volvo's Wheel";
??????????? Body = "Volvo's Body";
??????? }
???????
public
override
string Run()
??????? {
???????????
return
"Volvo is running";
??????? }
???????
public
override
string Stop()
??????? {
???????????
return
"Volvo is stoped";
??????? }
???????
public
override AbstractCar Clone()
??????? {
???????????
return (AbstractCar)this.MemberwiseClone();
??????? }
??? }
???
然后我們再來看看場景,我們定義一個Manage類,在這個場景中有一個人,一輛車和一條公路,代碼實現如下:
class
Manage
??? {
???????
public AbstractCar Car;
???????
public AbstractDriver Driver;
???????
public
???????
public
void Run(AbstractCar car,AbstractDriver driver,AbstractRoad road)
??????? {
??????????? Car = car.Clone();
??????????? Driver = driver.Clone();
??????????? Road = road.Clone();
??????? }
??? }
???
可以看到,在這個代碼中,場景只是依賴于那幾個抽象的類來實現的。最后我們再來實現一下客戶代碼,比如我現在要一輛Volvo車,一個叫“Anli”的女司機,在一條叫“Road
???
???
static
void
??????? {
??????????? Manage game = new Manage();
??????????? game.Run(new VolvoCar(),new Women("Anli",18),new Bituminous("Road1",1000));
??????????? Console.Write("CarRun:" + game.Car.Run() + "\n");
??????????? Console.Write("DriverName:" + game.Driver.name + "\n");
??????????? Console.Write("DriverSex:" + game.Driver.sex + "\n");
??????????? Console.Write("RoadName:" + game.Road.RoadName + "\n");
??????????? Console.Write("RoadType:" + game.Road.Type + "\n");
??????????? Console.Write("CarStop:" + game.Car.Stop() + "\n");
??????????? Console.Read();
??????? }
???
運行的結果是:
??? CarRun:Volvo is running
DriverName:Anli
DriverSex:Female
RoadName:Road1
RoadType:Bituminous
CarStop:Volvo is stoped
如果我現在想換成BORA車,讓我(kid-li)開,在一個水泥馬路上,我們只要更改Main函數中Run的實參。
game.Run(new BORACar(),new Man("kid-li",24),new Cement("Road1",1000));
運行結果是:
CarRun:BORA is running
DriverName:kid-li
DriverSex:Male
RoadName:Road1
RoadType:Cement
CarStop:BORA is stoped
這樣,經過簡單的更改,可以實現實現細節的變化。
現在我們再來看看原型模式的幾個要點:
1
、Prototype模式同樣用于隔離類對象的使用者和具體類型(易變類)之間的耦合關系,它同樣要求這些“易變類”擁有“穩定的接口”。
2
、Prototype模式對于“如何創建易變類的實體對象”采用“原型克隆”的方法來實現,它使得我們可以非常靈活地動態創建“擁有某些穩定接口”的新對象——所需工作僅僅是注冊一個新類的對象(即原型),然后在任何需要的地方不斷地Clone。
3
、Prototype模式中的Clone方法可以利用Object類的MemberwiseClone()或者序列化來實現深拷貝。
這里面我們再來說說淺拷貝和深拷貝。我想對于Prototype模式是很重要的。我覺得淺拷貝和深拷貝的關鍵區別是對于引用對象的拷貝。例如我們有一個類Class1,
public class Class1
{
??? int a;
??? int[] b;
}
我們用淺拷貝實現了兩個對象c1和c2,對于c1.a和c2.a,他們所有的內存空間是不一樣的,但是c1.b和c2.b,由于它們是引用類型,在淺拷貝時只是拷貝了一個地址給b成員,實際上c1.b和c2.b指向同一塊內存。
但如果我們用深拷貝,c1.b和c2.b指向的是不同的內存地址。那又如何實現深拷貝呢?我們可以利用序列化和反序列化來實現。
對于淺拷貝和深考貝的問題,我的同事TerryLee曾寫過一篇文章《 小議 .NET中的對象拷貝 》,我在這就不贅述了。