簡單工廠模式、工廠方法模式、反射工廠模式、抽象工廠模式
工廠模式在當初學習.net時就聽說過,記得當初實習的簡歷上寫著熟悉三層架構和工廠模式,其實當初並不會,只是聽說過。直到前些時候才去瞭解工廠模式,其實工廠模式還是很常用的,參考大話設計模式和網上的若干部落格,初步整理出四種版本的,簡單工廠模式、工廠模式、改進的反射工廠模式、抽象工廠模式。
首先先大概瞭解下實際運用背景,比如要設計一個整合平臺將停車場整合進來,而停車場有多個品牌供使用者選擇,這種情況就需要運用工廠模式。將停車場的特徵方法提取出來,每新加一種停車場時實現該方法即可,客戶端只需少許更改即可實現動態選擇產品。
首先不使用工廠模式實現:
public class ParkA { public void GetParkInfo() { Console.WriteLine("ParkA"); } } public class ParkB { public void GetParkInfo() { Console.WriteLine("ParkB"); } }
客戶端:
class Program
{
static void Main(string[] args)
{
ParkA park = new ParkA();
park.GetParkInfo();
Console.ReadLine();
}
}
這客戶端是用ParkA,又一客戶用ParkB,把這段程式碼去掉換成ParkB交給客戶,第三個客戶用ParkA,只能再改回ParkA,第一個客戶和第三個客戶明明一樣,但也沒法直接用(因為第二個客戶時已經改成ParkB了),如此很多時侯就是在做重複勞動,而且每賣一個都要開發人員根據其品牌修改一番。
1.簡單工廠
簡單工廠上場,面向介面程式設計,將選擇品牌的過程交給客戶,將停車場提取出介面,每個品牌都實現這個介面,然後提供一個工廠,使用者只要選擇自己的品牌即可。
public interface IPark { void GetParkInfo(); } public class ParkA : IPark { public void GetParkInfo() { Console.WriteLine("ParkA"); } } public class ParkB : IPark { public void GetParkInfo() { Console.WriteLine("ParkB"); } } public enum ParkTypeEnum { ParkA, ParkB } public class ParkFactory { public static IPark CreatePark(ParkTypeEnum parkType) { switch (parkType) { case ParkTypeEnum.ParkA: return new ParkA(); case ParkTypeEnum.ParkB: return new ParkB(); default: return null; } } }
客戶端:
class Program
{
static void Main(string[] args)
{
IPark park = ParkFactorys.ParkFactory.CreatePark(ParkTypeEnum.ParkA);
park.GetParkInfo();
Console.ReadLine();
}
}
當有新品牌時只需實現介面,修改工廠即可。而對於已有的品牌則無需修改。
這裡有個理論依據,里氏替換法則:任何接收父型別的地方,都應當能夠接收子型別,換句話說如果使用的是一個基類的話,那麼一定適用於其子類,而且程式察覺不出基類物件和子類物件的區別。
開放封閉原則:對擴充套件是開放的,而對修改是封閉的。
缺點:違反了開放封閉原則,對修改開放了,在增加一個新的品牌時必須相應增加工廠的switch分支。
2.工廠模式
相對簡單工廠變化之處,就是工廠發生了變化,將工廠也抽象出來一個工廠介面,裡面只有一個方法,用來建立例項。每個品牌都有自己的工廠,各自實現工廠介面即可。
public interface IPark
{
void GetParkInfo();
}
public class ParkA : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkA");
}
}
public class ParkB : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkB");
}
}
public interface IFactoryPark
{
IPark CreatePark();
}
public class ParkFactoryA : IFactoryPark
{
public IPark CreatePark()
{
return new ParkA();
}
}
public class ParkFactoryB : IFactoryPark
{
public IPark CreatePark()
{
return new ParkB();
}
}
客戶端:
class Program
{
static void Main(string[] args)
{
IFactoryPark factory = new ParkFactoryA();
IPark park=factory.CreatePark();
park.GetParkInfo();
Console.ReadLine();
}
}
這樣就符合了開放封閉原則,新加品牌同時新加相應的工廠,而無需修改原有的工廠。
缺點:品牌多了之後工廠也會隨之變得很多。
3.反射工廠模式
針對簡單工廠模式,還有一種改進,利用反射來封閉修改。修改工廠類,如下:
public class ParkFactory
{
public static IPark CreatePark(string typeName)
{
#region 方法一
//load中是程式集的名稱,也就是生成的DLL的名稱
//CreateInstance後面的是類的完整名稱,帶名稱空間
//IPark park = Assembly.Load("ParkFactorys").CreateInstance(typeName) as IPark;
#endregion
#region 方法二
//GetType的引數需是類的完整名稱,帶名稱空間
Type type = Type.GetType(typeName, true);
IPark park = Activator.CreateInstance(type) as IPark;
#endregion
return park;
}
}
客戶端:
class Program
{
static void Main(string[] args)
{
IPark park = ParkFactory.CreatePark("ParkFactorys.ParkA");
park.GetParkInfo();
Console.ReadLine();
}
}
4.抽象工廠模式
以上的三種的產品擴充套件都是針對同一個系列,當有多個時需要工廠裡將每個系列一個個的抽象,這時就要抽象工廠模式。
比如如下例子,除了整合停車場,現在也要整合汽車,這時就需要在工廠接口裡增加建立汽車介面的方法,抽象工廠是對工廠模式的繼續擴充。
public interface IPark
{
void GetParkInfo();
}
public class ParkA : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkA");
}
}
public class ParkB : IPark
{
public void GetParkInfo()
{
Console.WriteLine("ParkB");
}
}
public interface ICar
{
void Run();
}
public class CarA : ICar
{
public void Run()
{
Console.WriteLine("CarA Run");
}
}
public class CarB : ICar
{
public void Run()
{
Console.WriteLine("CarB Run");
}
}
public interface IFactory
{
IPark CreatePark();
ICar CreateCar();
}
public class ParkFactoryA : IFactory
{
public IPark CreatePark()
{
return new ParkA();
}
public ICar CreateCar()
{
return new CarA();
}
}
public class ParkFactoryB : IFactory
{
public IPark CreatePark()
{
return new ParkB();
}
public ICar CreateCar()
{
return new CarB();
}
}
客戶端:
class Program
{
static void Main(string[] args)
{
IFactory factory = new ParkFactoryA();
IPark park=factory.CreatePark();
park.GetParkInfo();
ICar car = factory.CreateCar();
car.Run();
Console.ReadLine();
}
}
最後簡單的總結:
簡單工廠:簡單實用,但違反開放封閉;
工廠方法:開放封閉,單一產品;
抽象工廠:開放封閉,多個產品;
反射工廠:可以最大限度的解耦。