SOLID(S): 單一職責原則

SOLID(S): 單一職責原則

Single responsibility principle (SRP)

定義: 只會有一種原因導致類的變更,也代表著一個類只負責一個職責。

舉例說明: 使用夾娃娃當範例,主要為投幣,操作,遊戲結果,三個流程
class ClawMachine {
    public void play() {
        //投幣
        Console.WriteLine("投10元");
        //抓取過程
        Console.WriteLine("移動");
        Console.WriteLine("抓取");
        //結果
        Console.WriteLine("領戰利品");
    }
}
class Player {
    static void Main(string[] args) {
        var clawMachine = new ClawMachine();;
        clawMachine.play();
        Console.ReadLine();
    }
}
輸出:
投10元
移動
抓取
領戰利品

code1: 在function層級實現SRP精神(SRP原始定義為在Class層級),把投幣,操作,遊戲結果,三個流程拆成三個function

class ClawMachine {
    public void play() {
        InsertCoin();
        Operating();
        Result();
    }
    public void InsertCoin() { //投幣
        Console.WriteLine("投10元");
    } 
    public void Operating() { //抓取過程
        Console.WriteLine("移動");
        Console.WriteLine("抓取");
    }
    public void Result() { //結果
        Console.WriteLine("領戰利品");
    }
}
class Player {
    static void Main(string[] args) {
        var clawMachine = new ClawMachine(); ;
        clawMachine.play();
        Console.ReadLine();
    }
}
輸出:
投10元
移動
抓取
領戰利品

code2: 在Class的層級上實現原始SRP定義,把投幣,操作,遊戲結果,三個流程拆成三個Class

  class Coin { //投幣
    public void InsertCoin() {
        Console.WriteLine("投10元");
    }
}
class Operate { //抓取過程
    public void Operating() {
        Console.WriteLine("移動");
        Console.WriteLine("抓取");
    }
}
class PlayResult { //結果
    public void Result() {
        Console.WriteLine("領戰利品");
    }
}
class ClawMachine {
    public void play() {
        var coin = new Coin();
        var operate = new Operate();
        var playResult = new PlayResult();

        coin.InsertCoin();
        operate.Operating();
        playResult.Result();
    }
}
class Player {
    static void Main(string[] args) {
        var clawMachine = new ClawMachine(); ;
        clawMachine.play();
        Console.ReadLine();
    }
}
輸出:
投10元
移動
抓取
領戰利品

SRP優點:
降低每個Class內的複雜度,可讀性高,方便擴充/維護,Class間都有其負責的職責,假如今天娃娃機沒讓你夾到,沒有戰利品可以拿,你可能選擇再投10元或改砸機台,這時你就一目瞭然的知道要直接在PlayResult類裡,進行擴充結果行為。

SRP缺點:
如果你把每個都做類層級的SRP規劃,會使得類數變多,使得各類之間的耦合提高,假如今天將Operate類又拆成移動(上,下,左,右,抓)五個類,這些組合行為,將會使得程式類之間的複雜性提高不少,這時直接在Operate類裡拆成5個function,則方便不少。

心得:
SRP不是鐵則,依照每個人的使用情況,和預估未來可能會擴充的部分,去規劃或重構,使得整個程式好讀,好擴充為重,也不用執著於要在class層級上實現SRP,有時候改在介面(interface)層級來實踐SRP精神,會變得方便許多。

例如:
今天有新機台,投幣改成投50元,抓取過程改用聲控的,有夾到商品輸入地址直接寄到你家,商品再返回機台,會發現這三種流程(投幣,抓取過程,結果)的實現方式都變了,唯一不變的則是這三個流程依然存在,你只需要讓ClawMachine類繼承這三種介面,並直接在新機台(類)裡,實作介面的新方法。