Design Patterns of GoF
對 GoF design patterns 的理解摘要。
Creational Design Patterns
1. Abstract Factory
TODO
2. Builder
TODO
3. Factory Method
- 使用 factory 建立新物件,建立新物件的邏輯集中在 factory
 
class MyFactory {
    public IAnimal createAnimal(string env) {
        switch (env) {
            case "desert" : return new Lion();  // Lion implements interface: IAnimal
            case "forest" : return new Rabbit();
            case "ocean"  : return new Dolphin();
        }
    }
}
4. Prototype
TODO
5. Singleton
- 確保只有單例(instance) 存在
 - 例如 
工廠物件或是管理器物件,就可能應用單例模式。 - 沒有特別意義時候,沒必要強加單例模式。
 
class Solo {
    private static readonly Solo instance = new Solo();
    // static constructor makes compiler not to mark type as beforefieldinit
    static Singleton() { }
    private Singleton() { }
    public static Solo Instance
    {
        get { return instance; }
    }
}
5.1. Monostate
利用私有成員達到類似 Singleton 的效果,無論實例化多少個物件,
背後對應的都是同樣的 private static member。
class Monostate
{
    private static int _num;
    public int Num
    {
        get => _num;
        set => _num = value;
    }
}
Structural Design Patterns
6. Adapter
TODO
7. Bridge
TODO
8. Composite
TODO
9. Decorator
動態替既有功能添加不同的行為。wiki
- Decorator 與原來的類有一樣的 interface
 - Decorator 包裹原來的類,成為其中被操控的 Component
 - 使用類繼承也可以達到修改行為,但是類繼承需要設計時候就決定好,Decorator模式可以在運行式修改行為。
 
class Car {
    public virtual void Move() {
        Console.WriteLine($"moving at {speed}");
    }
}
class abstract CarDecorator : Car {
    protected Car component;
    public void CarDecorator(Car c) { this.component = c; }
    public override void Move() {
        this.component.Move();
    }
}
// 繼承 Decorator 添加不同行為即可
class OldCar : CarDecorator {
    public override void Move() {
        base.Move();
        if (this.component.Age > 10) {
            Console.WriteLine("Warning! Must stop to rest within 2 hours.");
        }
    }
}
// 使用方式
OldCar oldCar = new OldCar();
// 需要依照運行時候狀態,也可如此設定:
oldCar.SetRuntimeStatus("hot");
// 之後當成一般對象使用
Car car = (Car)oldCar;
car.Move();
10. Façade
對複雜操作,利用一個 單一的通用界面,讓使用者可以進行 簡單的操作。
將複雜的操作隱藏於 Façade 之下。
需要使用者都同意接受 Façade 單一通用界面的規範,才有意義。
11. Flyweight
TODO
12. Proxy
TODO
Behavior Design Patterns
13. Chain of Responsibility
TODO
14. Command
將類似的動作使用統一的 interface 操作,具體動作內容因實作而不同。
abstract class MyCommand {
    protected Subject doer;
    public MyCommand(Subject doer) { 
        this.doer = doer;
    }
    
    abstract public void Execute()
}
class AlphaCommand : MyCommand {
    public override void Execute() {
        doer.DoSomethingAlphaNeeds();
    }
}
// 使用統一的界面操作
MyCommand a = AlphaCommand(user);
MyCommand b = BetaCommand(user);
a.Execute();
b.Execute();
14.1 Active Object
Command 模式的一種應用,可以控制多執行緒的運作,也叫做 RTC (Run To Completion)
engine 中的一個 Command 物件會在執行完成時候,將自身的複製物件放到 鏈接(commands) 尾部。
class ActiveObjectEngine
{
    List commands;
    public void AddCommand(Command c) => commands.Add(c);
    public void Run() {
        while (commands.Count > 0) {
            var c = command[0];
            commands.RemoveAt(0);
            c.Execute();
        }
    }
}
15. Interpreter
TODO
16. Iterator
TODO
17. Mediator
在使用者不需知情的狀況下,利用 Mediator 將兩個物件關聯起來,
進行互相協同的作業,兩個關聯的物件彼此間無需知道對方存在,
也無需知道 Mediator 的存在。
例如 Mediator 利用 TextBox 的 OnChanged event 觸發,
更新 ListBox 對應的 ListItem。
ListBox 或 TextBox 都無需事先知道,只要 Mediator 協助綁定事件即可。
18. Memento
TODO
19. Observer
TODO
20. State
TODO
21. Strategy
類似 22.Template Method,但提供更多的彈性,
各個 method 宣告於 interface 中,
將 組合各個 method 的 策略 實作在 AppRunner 中。
class AppRunner
{
    public App app { get; set; }
    public void Run() {
        app.Init();
        while(!app.DoJob()) {
            Sleep(1);
        }
        app.Clean();
    }
}
class BillingApp : App
{
    public void Init() {...} //實作 Init(), DoJob()...
    public static void Main(string[] args) {
        var app = new AppRunner() { App = new BillingApp() };
        app.Run();
    }
}
22. Template Method
製作一個模板 class, 只規定組合各個 method 的方式,
繼承的 class 負責實作各個 method 的細節。
class App
{
    protected void Init();   //由繼承類別實作
    protected bool DoJob();  //由繼承類別實作
    protected void Clean();  //由繼承類別實作
    public void Run()
    {
        Init();
        while(!DoJob()) { 
            Sleep(1); 
        }
        Clean();
    }
}
23. Visitor
TODO
Others
Null Object
可以製造一個什麼都不做的 Null 替代物件。
class User {
    public abstract bool DoSomething();
    public static readonly User NULL = new NullUser();
    private class NullUser : User {
        public override bool DoSomething() {
            return false; // do nothing.
        }
    }
}