設計模式系列
目的:定義一個簡單工廠,傳不同參數取得不同類別物件。
為什麼要用簡單工廠呢?
目的很簡單就是:做抽象與降低耦合。
什麼是抽象?
抽象就是在抽取事物的本質東西,剃除次要表面東西,這樣說可能不理解...
再把它具體化一下,把現實當中的某個東西,用程式表示出一個類或介面。
EX:例如香蕉、頻果、都是水果類。
耦合:就是你的模組與模組之間的依賴程度...(就是你的程式黏性,小心牽一髮動全身阿)。
以下就是簡單工廠的範例,分別由interface和abstract class用法
interface部分
class Program
{
static void Main(string[] args)
{
Ifruit iFruit = SimpleFactory.ActEat("A");
iFruit.Eat();
}
}
public interface Ifruit
{
void Eat();
}
public class SimpleFactory
{
public static Ifruit ActEat(string fruitType)
{
switch (fruitType)
{
case "A":
return new Apple();
case "B":
return new Banana();
default:
return new Other();
}
}
}
class Apple : Ifruit
{
public void Eat() => Console.WriteLine("我要吃頻果");
}
class Banana : Ifruit
{
public void Eat() => Console.WriteLine("我要吃香蕉");
}
class Other : Ifruit
{
public void Eat() => Console.WriteLine("我不知道要吃什麼...");
}
abstract class寫法
class Program
{
static void Main(string[] args)
{
Fruit Fruit = SimpleFactory.ActEat("A");
Fruit.Eat();
}
}
public abstract class Fruit
{
public abstract void Eat();
}
public class SimpleFactory
{
public static Fruit ActEat(string fruitType)
{
switch (fruitType)
{
case "A":
return new Apple();
case "B":
return new Banana();
default:
return new Other();
}
}
}
class Apple : Fruit
{
public override void Eat() => Console.WriteLine("我要吃頻果");
}
class Banana : Fruit
{
public override void Eat() => Console.WriteLine("我要吃香蕉");
}
class Other : Fruit
{
public override void Eat() => Console.WriteLine("我不知道要吃什麼...");
}
class Program
{
static void Main(string[] args)
{
Operation oper = OperationFactory.OperationCreate("+");
oper.NumberA = 1;
oper.NumberB = 2;
Console.WriteLine(oper.GetResult());
}
}
public class Operation
{
public int NumberA { get; set; }
public int NumberB { get; set; }
public virtual int GetResult()
{
int result = 0;
result = NumberA + NumberB;
return result;
}
}
public class OperationAdd : Operation
{
public override int GetResult()
{
return NumberA + NumberB;
}
}
public class OperationSub : Operation
{
public override int GetResult()
{
return NumberA - NumberB;
}
}
public class OperationFactory
{
public static Operation OperationCreate(string oper)
{
switch (oper)
{
case "+":
return new OperationAdd();
case "-":
return new OperationSub();
default:
return new Operation();
}
}
}
缺點:違反OCP原則,因為每次加一個物件,都要針對簡單工廠進行修改,
那怕是加一個switch case,仍然違背"不改代碼"原則
註記:
工廠方法:每種產品由一個工廠創建,一個工廠保存一個NEW基本完美,完全遵循,不改"程式"原則
抽象工廠:僅僅工廠方法複雜化,保存多個new,大工程會用上
案例:你要串接很多第三方支付,例如:你的線上付款,當中有很多家第三方支付,這時候可以
把它簡化變成,金流→有很多家第三支付→都有線上刷卡動作,寫一個現成簡化sample出來
簡單工廠,可以透過反射的做法方式去改良,後面的範例,我在補充上去^^
備註:
針對很容易變化的地方,以一個單獨的「類別」來處理它。
//想增加功能時,更改工廠類別。
補充加入小案例,來追加測試
public interface IAventurer
{
string GetType();
}
public class Archer : IAventurer
{
public string GetType()
{
Console.WriteLine("我是弓箭手");
return typeof(Archer).Name;
}
}
public class Warrior : IAventurer
{
public string GetType()
{
Console.WriteLine("我是鬥士");
return typeof(Warrior).Name;
}
}
public class TrainingCamp
{
public static IAventurer tranAdventurer(string type)
{
switch (type)
{
case "archer":
Console.WriteLine("訓練一名弓箭手");
return new Archer();
case "warrior":
Console.WriteLine("訓練一名鬥士");
return new Warrior();
default: return null;
}
}
}
public class TrainingCampTest
{
[Test]
public void Test()
{
IAventurer memberA = TrainingCamp.tranAdventurer("archer");
IAventurer memberB = TrainingCamp.tranAdventurer("warrior");
Assert.AreEqual(memberA.GetType(), "Archer");
Assert.AreEqual(memberB.GetType(), "Warrior");
}
}
元哥的筆記