2013年7月24日 星期三

設計模式:責任鏈模式 (Chain-of-responsibility Pattern)

責任鏈模式 (Chain-of-responsibility Pattern),以下程式碼以 C# 為例

說明:
有幾個物件都能處理某種請求,但處理的能範圍(權限)不同,
當這個物件沒有處理的權限時,能夠將這個請求,傳遞給下一個物件繼續處理。

範例:
員工請事假,經理只能批准2天的事假,協理只能批准5天的事假,超過五天須由總經理批准。

希望達成如下的效果
static void Main(string[] args)
{
    // 管理者初始化
    Manager a1 = new Manager("阿福"); // 經理
    Director a2 = new Director("技安"); // 協理
    GeneralManager a3 = new GeneralManager("宜靜"); // 總經理
    a1.SetUpManager(a2); // 設定經理的上級為協理
    a2.SetUpManager(a3); // 設定協理的上級為總經理

    // 假單初始化
    LeaveRequest leaveRequest = new LeaveRequest(); // 假單
    leaveRequest.Name = "大雄"; // 員工姓名

    leaveRequest.DayNum = 1; // 請假天數
    a1.RequestPersonalLeave(leaveRequest);// 送出1天的假單

    leaveRequest.DayNum = 3; // 請假天數
    a1.RequestPersonalLeave(leaveRequest);// 送出3天的假單

    leaveRequest.DayNum = 7; // 請假天數
    a1.RequestPersonalLeave(leaveRequest);// 送出7天的假單

    leaveRequest.DayNum = 10; // 請假天數
    a1.RequestPersonalLeave(leaveRequest);// 送出10天的假單

    Console.Read();
}
執行結果: 
經理 阿福 已批准 大雄1天的事假
協理 技安 已批准 大雄3天的事假
總經理 宜靜 已批准 大雄7天的事假
總經理 宜靜 要再了解 大雄10天的事假原因

實現重點在於,負責處理的物件,要能設定當自己沒辦法處理時,要將請求丟給誰。
並判斷,遇到不能處理的請求時,繼續將請求傳遞給下一個負責處理的物件。

其餘程式碼
// 管理者處理事假申請的抽象類別
abstract class ManagerHandler
{
    protected string name;
    protected ManagerHandler upManager; // 上一級的管理者

    public ManagerHandler(string name)
    {
        this.name = name;
    }

    // 設定上一級的管理者
    public void SetUpManager(ManagerHandler upManager)
    {
        this.upManager = upManager;
    }

    // 事假處理
    abstract public void RequestPersonalLeave(LeaveRequest leaveRequest);
}

// 經理
class Manager : ManagerHandler
{
    public Manager(string name) : base(name) { }

    public override void RequestPersonalLeave(LeaveRequest leaveRequest)
    {
        if (leaveRequest.DayNum <= 2)
        {
            // 2天以內,經理可以批准
            Console.WriteLine("經理 {0} 已批准 {1}{2}天的事假", this.name, leaveRequest.Name, leaveRequest.DayNum);
        }
        else
        {
            // 超過2天,轉呈上級
            if (null != upManager)
            {
                upManager.RequestPersonalLeave(leaveRequest);
            }
        }
    }
}

// 協理
class Director : ManagerHandler
{
    public Director(string name) : base(name) { }

    public override void RequestPersonalLeave(LeaveRequest leaveRequest)
    {
        if (leaveRequest.DayNum <= 5)
        {
            // 5天以內,經理可以批准
            Console.WriteLine("協理 {0} 已批准 {1}{2}天的事假", this.name, leaveRequest.Name, leaveRequest.DayNum);
        }
        else
        {
            // 超過5天,轉呈上級
            if (null != upManager)
            {
                upManager.RequestPersonalLeave(leaveRequest);
            }
        }
    }
}

// 總經理
class GeneralManager : ManagerHandler
{
    public GeneralManager(string name) : base(name) { }

    public override void RequestPersonalLeave(LeaveRequest leaveRequest)
    {
        if (leaveRequest.DayNum <= 7)
        {
            // 7天以內,總經理批准
            Console.WriteLine("總經理 {0} 已批准 {1}{2}天的事假", this.name, leaveRequest.Name, leaveRequest.DayNum);
        }
        else
        {
            // 超過7天以上,再深入了解原因
            Console.WriteLine("總經理 {0} 要再了解 {1}{2}天的事假原因", this.name, leaveRequest.Name, leaveRequest.DayNum);
        }
    }
}


// 假單
class LeaveRequest
{
    // 姓名
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    // 天數
    private int dayNum;
    public int DayNum
    {
        get { return dayNum; }
        set { dayNum = value; }
    }
}

相關連結:設計模式整理列表

沒有留言:

張貼留言