摘要:[ASP.NET] IoC (Inversion of Control) 實作工廠模式
前言
IoC 全名 Inversion of Control,中文稱 控制反轉,
IoC 是設計模式的一種,主要用來降低偶合性並且能夠抽換工作類別,
因為當程式開發到一定的規模時,程式偶合性越高之後的維護就越困難,
並且會造成動了一個地方的程式卻要更改一堆連帶的程式碼問題。
範例
舉個例來說,一般類別間呼叫使用的撰寫方法如下:
我本身為一個MAN類別,小狗為一個Dog類別,
MAN類別中有: goEat方法(去吃東西)、goMove方法(去動動)、goSleep方法(去睡覺),
DOG類別中有: eat方法(吃)、move方法(動)、sleep方法(睡),
程式碼如下:
static void Main(string[] args)
{
Console.WriteLine("主人:我來了!");
Dog dog = new Dog();
bool flag = true;
while (flag)
{
string cmd = Console.ReadLine();
if (cmd == "eat")
goEat(dog);
else if (cmd == "move")
goMove(dog);
else if (cmd == "sleep")
goSleep(dog);
else
{
flag = false;
Console.WriteLine("沒事,我走了!");
}
}
Console.ReadLine();
}
static void goEat(Dog dog)
{
dog.eat();
}
static void goMove(Dog dog)
{
dog.move();
}
static void goSleep(Dog dog)
{
dog.sleep();
}
執行結果如下:
看起來好像其實很正常沒甚麼問題,
但是,如果女朋友說: 寶貝~我又想養一隻貓耶,我要養~ >.^ 咪揪
這時該怎麼辦?
上面這種程式碼是不是就變成要去修改原始程式,要多加了貓的判斷跟動作?,如下:
static void Main(string[] args)
{
Console.WriteLine("主人:我來了!");
Console.Write("你要找(dog/cat)?: ");
string animalType = Console.ReadLine();
if (animalType == "cat")
{
Cat cat = new Cat();
bool flag = true;
while (flag)
{
Console.Write("下指令(eat/move/sleep/bye): ");
string cmd = Console.ReadLine();
if (cmd == "eat")
goEat(cat);
else if (cmd == "move")
goMove(cat);
else if (cmd == "sleep")
goSleep(cat);
else
{
flag = false;
Console.WriteLine("沒事,我走了!");
}
}
}
else if (animalType == "dog")
{
Dog dog = new Dog();
bool flag = true;
while (flag)
{
Console.Write("下指令(eat/move/sleep/bye): ");
string cmd = Console.ReadLine();
if (cmd == "eat")
goEat(dog);
else if (cmd == "move")
goMove(dog);
else if (cmd == "sleep")
goSleep(dog);
else
{
flag = false;
Console.WriteLine("沒事,我走了!");
}
}
}
Console.ReadLine();
}
static void goEat(Dog dog)
{
dog.eat();
}
static void goMove(Dog dog)
{
dog.move();
}
static void goSleep(Dog dog)
{
dog.sleep();
}
static void goEat(Cat cat)
{
cat.eat();
}
static void goMove(Cat cat)
{
cat.move();
}
static void goSleep(Cat cat)
{
cat.sleep();
}
各位應該都發現了,
因為多了一隻寵物導致程式碼變得很冗長又複雜很難維護,而如果女朋友哪天心血來潮又要養什麼的話,可想而知慘兮兮。
接下來讓我們使用 IoC 來設計看看,
我重新設計類別,產生了一個 IAnimal 的介面,再多了一個Bird類別,並且Dog、Cat、Bird三個類別都實作 IAnimal 介面,如下:
接下來,我新增一個Factory 類別,使用 Factory Class 控管這些小動物類別,
並加入一個 CallAnimal 方法作為入口,用來實際產生該類別。
程式碼如下:
public static IAnimal CallAnimal(string type)
{
switch (type)
{
case "dog":
return new Dog();
case "cat":
return new Cat();
case "bird":
return new Bird();
default:
return null;
}
}
這邊使用swicth來選擇要分配哪一個物件回去,因為Dog、Cat、Bird三類別都有實作 IAnimal 介面,
所以回傳型別直接使用 IAnimal 介面,
接下來修改MAN類別,如下,
static void Main(string[] args)
{
Console.WriteLine("主人:我來了!");
Console.Write("你要找(dog/cat/bird)?: ");
string animalType = Console.ReadLine();
IAnimal animal = AnimalFactory.CallAnimal(animalType);
if (animal != null)
{
bool flag = true;
while (flag)
{
Console.Write("下指令(eat/move/sleep/bye): ");
string cmd = Console.ReadLine();
if (cmd == "eat")
goEat(animal);
else if (cmd == "move")
goMove(animal);
else if (cmd == "sleep")
goSleep(animal);
else
{
flag = false;
Console.WriteLine("沒事,我走了!");
}
}
}
Console.ReadLine();
}
static void goEat(IAnimal anim)
{
anim.eat();
}
static void goMove(IAnimal anim)
{
anim.move();
}
static void goSleep(IAnimal anim)
{
anim.sleep();
}
這邊我使用 IAnimal 介面去接回傳回來的動物物件,因為 dog、cat、bird三類別都有實作 IAnimal 介面方法,
所以都能夠使用 eat()、move()、sleep()方法,而我們只需要依照要使用的方法去呼叫就可以了,
看完上例應該有發現之後不管再新增多少動物,在此設計模式下都可以簡單的抽換動物類別,
只要新增其對應的動物類別跟稍為修改 AnimalFactory 類別的 swicth 即可,拼拼裝裝就能夠完成,女朋友要養什麼都沒問題啦!!
2012/09/19 更新:
後來想了一下,因為這種方法最後還是會需要去動到 Factory 程式,所以我再稍為修改一下,
讓程式之後只需要讀取 app.config 組態檔設定即可,也就是只要新增一個Animal Class與修改組態檔即可,
方法如下:
1.加入 app.config 組態檔
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="AnimalObject1" value="Dog" />
<add key="AnimalObject2" value="Cat" />
<add key="AnimalObject3" value="Bird" />
</appSettings>
</configuration>
我加入三個 AnimalObject 設定字串,各代表不同動物類別。
2.修改 AnimalFactory Class如下:
public static IAnimal CallAnimal(string animalType)
{
List objNames = new List<string>();
foreach (string key in System.Configuration.ConfigurationManager.AppSettings.Keys)
{
if (key.IndexOf("AnimalObject") > -1) {
objNames.Add(System.Configuration.ConfigurationManager.AppSettings[key].ToString());
}
}
foreach (string name in objNames)
{
if (name == animalType)
{
Type oType = Type.GetType(name);
IAnimal oAnimal = (IAnimal)Activator.CreateInstance(oType);
return oAnimal;
}
}
return null;
}
這裡的處理方式為,取得 appSetting 設定字串並且尋找是否有 AnimalObject 的字串,
找到之後產生該物件實體回傳,如此感覺上更方便了。
以上為使用心得備記,如有錯誤請多指教,謝謝。
範例程式碼
參考資料
http://baike.baidu.com/view/146665.htm
http://eoffice.im.fju.edu.tw/phpbb/viewtopic.php?p=29589
http://www.dotblogs.com.tw/hatelove/archive/2011/05/26/refactoring-using-interface-to-ioc.aspx
http://blog.csdn.net/code6421/article/details/1282139
以上文章敘述如有錯誤及觀念不正確,請不吝嗇指教
如有侵權內容也請您與我反應~謝謝您 :)