|
Design Pattern - Factory Method
|
| (史帝芬, 2007/05/13, hi.steven@gmail.com) |
某家銀行有兩家分行,分別為台灣分行及香港分行,每家分行裡有三 種職位的人 -- Manager、Team Leader、Employee,現在要設計一套系統,用來印出薪水條, 在考量這家分行在不久的將來將於中國及英國設分行,系統應保留於設立中國分行、英國分行時, 只需加入新的有關中國、英國分行薪水計算的程式,不需修改既有程式,程式應如何設計? 這裡將以Factory Method Pattern來設計這套系統,而且會有許多不 同的實作方式,讓讀者了解一下,同樣的Pattern在不同的思考模式下,也會不同的型式。
using System;
namespace Factory
{
public abstract class Bank
{
public PayList create(string position)
{
PayList p = createPayList(position);
return p;
}
protected abstract PayList createPayList(string position);
}
public class TaiwanBranch : Bank
{
protected override PayList createPayList(string position)
{
switch (position)
{
case "Manager":
return new TaiwanManagerPayList();
case "TeamLeader":
return new TaiwanTeamLeaderPayList();
default:
return new TaiwanEmploiyeePayList();
}
}
}
public class HongKongBranch : Bank
{
protected override PayList createPayList(string position)
{
return new HongKongManagerPayList();
}
}
public abstract class PayList
{
protected double basePay;
protected double bonus;
protected double taxRating;
public abstract double revenue();
public abstract double tax();
public abstract double paying();
public void printPayList()
{
Console.WriteLine("薪水: {0}", revenue());
Console.WriteLine("所得稅: {0}", tax());
Console.WriteLine("應付: {0}", paying());
}
}
public class TaiwanManagerPayList : PayList
{
public TaiwanManagerPayList()
{
basePay = 80000;
bonus = 20000;
taxRating = 0.21;
}
public override double revenue()
{
return basePay + bonus;
}
public override double tax()
{
return revenue() * taxRating;
}
public override double paying()
{
return revenue() - tax();
}
}
public class TaiwanTeamLeaderPayList : PayList
{
public TaiwanTeamLeaderPayList()
{
basePay = 60000;
bonus = 3000;
taxRating = 0.13;
}
public override double revenue()
{
return basePay + bonus;
}
public override double tax()
{
return revenue() * taxRating;
}
public override double paying()
{
return revenue() - tax();
}
}
public class TaiwanEmploiyeePayList : PayList
{
public TaiwanEmploiyeePayList()
{
basePay = 40000;
bonus = 0;
taxRating = 0.06;
}
public override double revenue()
{
return basePay + bonus;
}
public override double tax()
{
return revenue() * taxRating;
}
public override double paying()
{
return revenue() - tax();
}
}
public class HongKongManagerPayList : PayList
{
public HongKongManagerPayList()
{
basePay = 100000;
bonus = 30000;
taxRating = 0.32;
}
public override double revenue()
{
return basePay + bonus;
}
public override double tax()
{
return basePay * taxRating;
}
public override double paying()
{
return revenue() - tax();
}
}
public class HongKongTeamLeaderPayList : PayList
{
public HongKongTeamLeaderPayList()
{
basePay = 68000;
bonus = 12000;
taxRating = 0.20;
}
public override double revenue()
{
return basePay + bonus;
}
public override double tax()
{
return basePay * taxRating;
}
public override double paying()
{
return revenue() - tax();
}
}
public class HongKongEmployeePayList : PayList
{
public HongKongEmployeePayList()
{
basePay = 50000;
bonus = 0;
taxRating = 0.09;
}
public override double revenue()
{
return basePay + bonus;
}
public override double tax()
{
return basePay * taxRating;
}
public override double paying()
{
return revenue() - tax();
}
}
class Program
{
static void Main(string[] args)
{
Bank twBranch = new TaiwanBranch();
Console.WriteLine("Manager");
PayList twManager = twBranch.create("Manager");
twManager.printPayList();
Console.WriteLine("Team Leader");
PayList twTeamLeader = twBranch.create("TeamLeader");
twTeamLeader.printPayList();
Console.WriteLine("Employee");
PayList twEmployee = twBranch.create("Employee");
twEmployee.printPayList();
Console.ReadLine();
}
}
}
未來增加中國分行時,程式只要增加ChinaBranch、ChinaManagerPayList、 ChinaTeamLeaderPayList、ChinaEmployeePayList四個class即可,不需修改到既有程式。 上面的程式有個問題,就是programmer需了解Bank及PayList兩個介面,如 果我們希望programmer只要了解Bank這個介面,可以將class Bank改寫如下,Bank合成PayList, 提供外界所需的介面,這樣programmer只要透過class Bank就可以完成所有需要的動作了。
public abstract class Bank
{
private PayList payList;
public void create(string position)
{
payList = createPayList(position);
}
protected abstract PayList createPayList(string position);
public double revenue()
{
return payList.revenue();
}
public double tax()
{
return payList.tax();
}
public double paying()
{
return payList.paying();
}
public void printPayList()
{
payList.printPayList();
}
}
…
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Manager");
Bank twBranch = new TaiwanBranch();
twBranch.create("Manager");
twBranch.printPayList();
Console.WriteLine("Team Leader");
twBranch.create("TeamLeader");
twBranch.printPayList();
Console.WriteLine("Employee");
twBranch.create("Employee");
twBranch.printPayList();
Console.ReadLine();
}
}
第2個程式穩藏了PayList的實作細節,讓Bank只要操作PayList這個介面 即可得到想要的結果,在實際應用中,到底要用第一或第二種方式,是根據需求而定,並沒有絕對 的優劣之分。 |