設計模式

2023-06-27 18:00:44

前言

​ 設計模式和設計原則從程式設計開始就接觸了,但那個時候不知其所以然,工作一段時間後,再看設計模式,發現這東西在專案中或者框架中普遍存在。和以前的知識就融會貫通了。於是我打算自己寫一篇關於設計原則與設計模式博文吧。

為什麼要設計模式和設計原則呢?

  1. 提高程式碼質量和可維護性:設計模式和設計原則強調良好的軟體設計原則和實踐,例如高內聚、低耦合、單一職責原則等。通過遵循這些原則,可以編寫結構清晰、易於理解和維護的程式碼。
  2. 促程序式碼重用:設計模式鼓勵將可重用的元件和模組進行抽象和封裝,使其可以在不同的上下文中重複使用。這樣可以減少重複編寫程式碼的工作量,提高開發效率
  3. 增加程式碼的可延伸性和靈活性:設計模式和設計原則提供了一種靈活的架構和設計方法,使系統能夠輕鬆地擴充套件和適應變化。通過遵循開閉原則、依賴倒置原則等設計原則,可以使系統更容易進行功能擴充套件和修改。
  4. 促進團隊合作和交流:設計模式提供了一種共用的設計詞彙和概念,使團隊成員能夠更容易地理解和溝通設計決策。它們提供了一種通用的語言,促進了團隊合作和程式碼共用。

總的來說,設計模式和設計原則是經過驗證和廣泛應用的最佳實踐和經驗總結。它們幫助開發人員構建高質量的軟體系統,並提供瞭解決常見設計問題的方法。通過應用這些原則和模式,可以改善軟體的可維護性、可延伸性和可重用性,提高開發效率,並減少程式碼錯誤和重構的需求。

設計原則

單一原則

一個類只做一件事

class Animal{
       void run(string name){
           console.write(name+"能跑")
       }
}

var animal = new Animal()
       animal.run("狗")  
       animal.run("小鳥") // 小鳥不能跑

       /*
可以看到Animal類是單一原則的,只做一件事
方法之前也是單一原則的,當我們傳入小鳥就出現了問題
我們可以新增一個方法,這樣可以保證方式是單一原則,一個方法也做一件事,以後修改互不影響
*/

依賴倒置原則

就是面向介面程式設計,細節依賴抽象,抽象不依賴細節

例子:有一個食物類,我們應該把它抽象出來,讓具體的食物去實現食物介面,比如香蕉啊,蘋果啊,白米飯啊。這時假如有一個人要進食,只需要傳入食物介面,就可以了。

var people = new People();
people.eat(new Banana());
people.eat(new Apple());

// 食物介面
interface IFood
{
       // 味道
       string name{ get; set; }
   }
   
   // 香蕉
   class Banana : IFood
{
       public string name { get; set; }
}
// 蘋果
class Apple : IFood
{
       public string name { get; set; }
   }

// 人
class People
{
       public void eat(IFood food)
       {
           Console.WriteLine("我要吃"+ food.name);
       }
}

開閉原則

對擴充套件開放,對修改閉合

例子:有一個餵食的類,餵食的類關聯兩個物件,一個食物 一個是動物,食物應該是抽象的,動物應該也是抽象的,這樣我們以後要新增新的物件時,只需要實現對應的介面就行了,餵食類照樣工作

var feed = new Feed();

var dogFood = new DogFood(){value = "一號狗糧"};

var tigerFood = new DogFood(){value = "一號肉食"};

var dog = new List<Dog>() { new Dog(), new Dog() };
var tiger = new List<Tiger>() { new Tiger(), new Tiger() };

feed.StartFeed(dog, dogFood);
feed.StartFeed(tiger, tigerFood);


// 能吃東西的實現這個介面
interface IEat { void eat(IFoot foot); }

// 食物實現這個介面
interface IFoot { string value { get; set; } }

// 狗是動物
class Dog : IEat
{
       public void eat(IFoot foot)
       {
           Console.WriteLine("狗吃"+foot.value);
       }
}

   // 老虎是動物
   class Tiger : IEat
   {
       public void eat(IFoot foot)
       {
           Console.WriteLine("老虎吃"+foot.value);
       }
}


// 狗吃的食物
   class DogFood : IFoot
   {
       public string value { get; set; }
   }

class TigerFood : IFoot
{
       public string value { get; set; }
}

// 餵食類
class Feed
   {
       public void StartFeed(IEnumerable<IEat> eats,IFoot foot) { 

           foreach (IEat eat in eats)
           {
               eat.eat(foot);
           }
       }
}

里氏替換原則

父類別出現的地方,能用子類代替

interface IFood{ string name {get;set;} }

class Banana:IFood{
       string name {get;set;}
}
class Apple:IFood{
       string name {get;set;}
}

IFood food1 = new Banana();
IFood food2 = new Apple();

介面隔離原則

不要依賴不需要的介面,介面不要設計的太過龐大

public void StartFeed(IEnumerable<IEat> eats,IFoot foot) { 
   
       foreach (IEat eat in eats)
       {
           eat.eat(foot);
       }
}

/*

可以看到上面是滿足最小介面的,
如果IEat換成 IAnimal呢,就可能出現問題,
吃這個行為只能動物進行嗎?比如機器人吃電池呢
所以說,介面不要設計的太龐大,應該合理進行細分

*/

迪米特法則

一個模組對另一個模組應該要有儘可能少的瞭解,當要修改一個模組的時候影響的模組就小,使其功能獨立。

例子:有A和B物件,B裡面依賴了A,B在別的地方使用,B應該隱藏A

class A{
       void say(){
           console.write('aaa')
       }
}
class B{
       // 這裡使用禁止public
       private A _A;
       public B(){
           this._A = new A()
       }
       public say(){
           // 我覺得這裡是迪米特法則的核心
           this._B.say()
       }
}

class client{
       void main{
           B b = new B();
           b.say()
    }
}

設計模式

創造型模式(5個)

單例模式

全域性只有一個範例

class Example
{
       private static Example _Example;
       static Example()
       {
           _Example = new Example();
           Console.WriteLine("構造出來了哦");
       }
       public static Example GetExample() {

           return _Example;
       }
}

工廠方法模式

建立一個工廠介面,由子類去實現具體工廠的建立。工廠建立的物件稱其為產品。有了產品,當然要有建立產品介面。

例子

IShapeFactory shapeFactory = new CircleFactory();
// 或者 IShapeFactory shapeFactory = new RectangleFactory();

IShape shape = shapeFactory.CreateShape();
shape.draw();// 我是圓

/// <summary>
/// 圖型介面
/// </summary>
interface IShape
{
       void draw();
}

/// <summary>
/// 圓形類
/// </summary>
class Circle : IShape
{
       public void draw()
       {
           Console.WriteLine("我是一個圓");
       }
}
/// <summary>
/// 矩形類
/// </summary>
class Rectangle : IShape
{
       public void draw()
       {
           Console.WriteLine("我是一個矩形");
       }
}

/// <summary>
/// 圖型工廠
/// </summary>
interface IShapeFactory
{
       IShape CreateShape();
}

/// <summary>
/// 生成圓形的工廠
/// </summary>
class CircleFactory : IShapeFactory
{
       public IShape CreateShape()
       {
           return new Circle();
       }
}

/// <summary>
/// 生成矩形的工廠
/// </summary>
class RectangleFactory : IShapeFactory
{
       public IShape CreateShape()
       {
           return new Rectangle();
       }
}

抽象工廠模式

抽象工廠和工廠方法類似,只不過抽象工廠是一群工廠

範例

IGUIFactory factory = new CircleFactory();	// 這裡替換後,可以生成別的產品,
IColor color1 = factory.createColor();
IText text1 = factory.createText();

color1.render();
text1.render();

/// <summary>
/// 顏色介面
/// </summary>
interface IColor
{
       void render();
}
/// <summary>
/// 文字介面
/// </summary>
interface IText {
       void render();
}

/// <summary>
/// 帶顏色的圓
/// </summary
class CircleColor : IColor
{
       public void render()
       {
           Console.WriteLine("我是一個帶顏色的圓");
       }
}
/// <summary>
/// 帶文字的圓
/// </summary>
class CircleText : IText
{
       public void render()
       {
           Console.WriteLine("我是一個帶文字的圓");
       }
}

/// <summary>
/// 帶顏色的圓
/// </summary
class RectangleColor : IColor
{
       public void render()
       {
           Console.WriteLine("我是一個帶顏色的矩形");
       }
}
/// <summary>
/// 帶文字的圓
/// </summary>
class RectangleText : IText
{
       public void render()
       {
           Console.WriteLine("我是一個帶文字的矩形");
       }
}


/// <summary>
/// 圖型工廠
/// </summary>
interface IGUIFactory
{
       IColor createColor();
       IText createText();
}

/// <summary>
/// 生成圓形的工廠
/// </summary>
class CircleFactory : IGUIFactory
{
       public IColor createColor()
       {
           return new  CircleColor();
       }
       public IText createText()
       {
           return new CircleText();
       }
}

/// <summary>
/// 生成矩形的工廠
/// </summary>
class RectangleFactory : IGUIFactory
{
       public IColor createColor()
       {
           return new RectangleColor();
       }
       public IText createText()
       {
           return new RectangleText();
       }
}

建造者模式

將物件構建的過程和細節分離,如下

// 指導者,用來指導構建的類
AppleDirector appleDirector = new AppleDirector();
// 構造一個Q蘋果
AppleBuild build = new QAppleBuild();
appleDirector.SetAppleBuild(build);
Apple apple = appleDirector.Build();
apple.display();


/// <summary>
/// 蘋果類
/// </summary>
class Apple
{
       public string name { get; set; }
       public string color { get; set; }
       public void display() {
           Console.WriteLine(name);
           Console.WriteLine(color);
       }
}

/// <summary>
/// 抽象建造者
/// </summary>
abstract class AppleBuild{
       protected Apple _apple;
       public abstract void nameBuilder();
       public abstract void colorBuilder();
       public AppleBuild()
       {
           _apple = new Apple();
       }
       public Apple getApple() {
           return _apple;
       }
}

class QAppleBuild : AppleBuild
{
       public override void colorBuilder()
       {
           base._apple.color = "綠色";
       }
       public override void nameBuilder()
       {
           base._apple.name = "綠蘋果";
       }
}

class WAppleBuild : AppleBuild
{
       public override void colorBuilder()
       {
           base._apple.color = "紅色";
       }
       public override void nameBuilder()
       {
           base._apple.name = "紅蘋果";
       }
}

/// <summary>
/// 蘋果的指導者
/// </summary>
class AppleDirector
{
       private AppleBuild _appleBuild;
       public void SetAppleBuild(AppleBuild appleBuild)
       {
           _appleBuild = appleBuild;
       }
       public Apple Build() {
           this._appleBuild.colorBuilder();
           this._appleBuild.nameBuilder();
           return this._appleBuild.getApple();
       }
}

原型工廠模式

原型工廠模式通過克隆現有物件來建立新物件

ShapeFactory factory = new ShapeFactory();
factory.GetShape(nameof(Circle)).draw();
factory.GetShape(nameof(Rectangle)).draw();

abstract class Shape
{
       public abstract void draw();
       public abstract Shape clone();
}

class Circle : Shape
{
       public override Shape clone()
       {
           return new Circle();
       }
       public override void draw()
       {
           Console.WriteLine("我是一個圓");
       }
}

class Rectangle : Shape
{
       public override Shape clone()
       {
           return new Rectangle();
       }
       public override void draw()
       {
           Console.WriteLine("我是一個矩形");
       }
}

class ShapeFactory
{
       private Dictionary<string, Shape> shapeCache;
       public ShapeFactory()
       {
           shapeCache = new Dictionary<string, Shape>();
           shapeCache.Add(nameof(Circle), new Circle());
           shapeCache.Add(nameof(Rectangle), new Rectangle());
       }

       public Shape GetShape(string type) {

           if (shapeCache.ContainsKey(type))
           {
               return shapeCache[type].clone();
           }
           return null;
       }
}

結構型模式(7個)

介面卡模式

 介面卡模式意在轉換介面,它能夠使原本不能再一起工作的兩個類一起工作,所以經常用來在類庫的複用

IPlay play = new VideoAdapter(new Video());

interface IPlay
{
       void show();
}
class Video
{
       public void play()
       {
           Console.WriteLine("輸出視訊");
       }
}

/// <summary>
/// 介面卡,適配給IPlay使用
/// </summary>
class VideoAdapter : IPlay
{
       private Video video;
       public VideoAdapter(Video video)
       {
           this.video = video;
       }
       public void show()
       {
           video.play();
       }
}

橋接模式

將抽象和實現進行分離,兩者可以獨立地變化

//IShape shape = new Rectangle(new RedColor()); 具體的形狀和顏色可以任意變換,業務不受影響
IShape shape = new Rectangle(new BlueColor());
shape.draw();

/// <summary>
/// 形狀類
/// </summary>
interface IShape
{
       void draw();
}
class Circle : IShape
{
       private IColor color;
       public Circle(IColor color)
       {
           this.color = color;
       }
       public void draw()
       {
           Console.WriteLine("我是圓形");
           this.color.fill();
       }
}
class Rectangle : IShape
{
       private IColor color;
       public Rectangle(IColor color)
       {
           this.color = color;
       }
       public void draw()
       {
           Console.WriteLine("我是矩形");
           this.color.fill();
       }
}

/// <summary>
/// 顏色類
/// </summary>
interface IColor
{
       void fill();
}

/// <summary>
/// 紅色
/// </summary>
class RedColor : IColor
{
       public void fill()
       {
           Console.WriteLine("紅色");
       }
}

/// <summary>
/// 藍色
/// </summary>
class BlueColor : IColor
{
       public void fill()
       {
           Console.WriteLine("藍色");
       }
}

裝飾者模式

在物件新增新東西,不修改原來物件

// 普通咖啡
ICoffee coffee = new Coffee();

Console.WriteLine(coffee.GetDescription());
// 裝飾器裝飾
coffee = new QCoffee(coffee);
Console.WriteLine(coffee.GetDescription());

coffee = new WCoffee(coffee);
Console.WriteLine(coffee.GetDescription());

/// <summary>
/// 咖啡介面
/// </summary>
interface ICoffee
{
       string GetDescription();
       double GetCost();
}

class Coffee : ICoffee
{
       public double GetCost()
       {
           return 2;
       }
       public string GetDescription()
       {
           return "咖啡";
       }
}

/// <summary>
/// 裝飾器基礎類別
/// </summary>
abstract class CoffeeDecorato : ICoffee
{
       private ICoffee coffee;
       public CoffeeDecorato(ICoffee coffee)
       {
           this.coffee = coffee;
       }
       public virtual double GetCost()
       {
           return coffee.GetCost();
       }
       public virtual string GetDescription()
       {
           return coffee.GetDescription();
       }
}

class QCoffee : CoffeeDecorato
{
       public QCoffee(ICoffee coffee) : base(coffee)
       {
       }
       public override string GetDescription()
       {
           return base.GetDescription()+"q咖啡,得價錢10塊";
       }
       public override double GetCost()
       {
           return base.GetCost()+10;
       }
}

class WCoffee : CoffeeDecorato
{
       public WCoffee(ICoffee coffee) : base(coffee){}
       public override string GetDescription()
       {
           return base.GetDescription() + "w咖啡,得價錢20塊";
       }
       public override double GetCost()
       {
           return base.GetCost() + 20;
       }
}

組合模式

組合模式將物件組合成樹形結構,用來表示整體與部分的關係

File file1 = new File("檔案1");
File file2 = new File("檔案2");
Folder folder1 = new Folder("資料夾1");
Folder folder2 = new Folder("資料夾2");

folder1.add(file1);
folder2.add(file2);

folder2.add(folder1);

/// <summary>
/// 抽象公共屬性
/// </summary>
abstract class IFolderCommon
{
       public IFolderCommon(string name)
       {
           this.name = name;
       }
       public string name { get; set; }
}
/// <summary>
/// 檔案
/// </summary>
class File : IFolderCommon
{
       public File(string name): base(name){}
}

/// <summary>
/// 資料夾
/// </summary>
class Folder : IFolderCommon
{
       public List<IFolderCommon> _folder;
       public Folder(string name) : base(name)
       {
           this._folder = new List<IFolderCommon>();
       }
       public void add(IFolderCommon folder) { 
           this._folder.Add(folder);
       }
       public void remove(IFolderCommon folder)
       {
           this._folder.Remove(folder);
       }
}

外觀模式

使用者端不與子系統互動, 提供簡化的介面,降低使用者端與複雜系統的互動

/// <summary>
/// 庫存管理
/// </summary>
class InventorySystem{
       // 檢查庫存是否足夠
       public bool CheckStock(string id) {
           return false;
       }
}
/// <summary>
/// 訂單管理
/// </summary>
class OrderSystem
{
       // 建立訂單
       public string CreateOrder()
       {
           return "訂單號";
       }
}

/// <summary>
/// 電子商務外觀
/// </summary>
class ECommercePlatformFacade
{
       private InventorySystem _inventorySystem;
       private OrderSystem _orderSystem;

       public ECommercePlatformFacade()
       {
           _inventorySystem = new InventorySystem();
           _orderSystem = new OrderSystem();
       }
       // 使用者下單
       public void PlaceOrder(List<string> ids) { 

           foreach (string id in ids)
           {
               // 檢查庫存是否足夠
               if (_inventorySystem.CheckStock(id))
               {   // 建立訂單
                   _orderSystem.CreateOrder();
               }
           }
       }
}

/// <summary>
/// 使用者端
/// </summary>
class Client
{
       public void main() { 
           ECommercePlatformFacade platformFacade = new ECommercePlatformFacade();
           // 使用者批次下單
           platformFacade.PlaceOrder(new List<string>() { "1", "2" });
       }
}

享元模式

將類似的物件快取起來,以後重複使用,避免new開銷,注意物件釋放時機!

/// <summary>
/// 享元介面
/// </summary>
public interface IPlayer
{
       void AssignWeapon(string weapon);
       void Play();
}

/// <summary>
/// 實現類
/// </summary>
public class Player : IPlayer
{
       private string weapon;
       public void AssignWeapon(string weapon)
       {
           this.weapon = weapon;
       }

       public void Play()
       {
           Console.WriteLine(weapon);
       }
}

/// <summary>
/// 享元工廠
/// </summary>
public class PlayerFactory
{
       /// <summary>
       /// 快取起來,享元
       /// </summary>
       private Dictionary<string,IPlayer>  players;

       public PlayerFactory()
       {
           this.players = new Dictionary<string,IPlayer>();
       }
       public IPlayer GetPlayer(string weapon)
       {
           if (players.ContainsKey(weapon))
           {
               return players[weapon];
           }
           else
           {
               IPlayer player = new Player();
               player.AssignWeapon(weapon);
               players.Add(weapon, player);
               return player;
           }
       }
}

代理模式

通過代理的方式,間接的存取物件

// 統一介面
public interface ISubject
{
       void Request();
}

// 實現類
public class RealSubject : ISubject
{
       public void Request()
       {
           Console.WriteLine("come");
       }
}

// 代理類
public class Proxy: ISubject
{
       private RealSubject realSubject;
       public void Request()
       {
           if (realSubject == null)
           {
               realSubject = new RealSubject();
           }
           // 這裡進行代理
           realSubject.Request();
       }
}

// 使用者端
public class Client
{
       public void main() {
           Proxy proxy = new Proxy();
           proxy.Request();
       }
}

行為型模式(11個)

模板方法模式

提供一套模板,走特定的程式,然後讓子類去繼承它,重寫一些通用的邏輯

Template temp = new TimeTask();
temp.run();

// 模板類
abstract class Template
{
    public void run()
    {
        // 走特定的流程
        Start();
        Add();
        End();
    }
    protected void Start()
    {
        Console.WriteLine("任務開");
    }
    /// <summary>
    /// 提供一個模板
    /// </summary>
    protected abstract void Add();
    protected void End()
    {
        Console.WriteLine("任務結束");
    }
}

// 實現類
class TimeTask : Template
{
    protected override void Add()
    {
        Console.WriteLine("中間插入的內容");
    }
}

// 使用者端
class Client
{
    void main() {
        Template temp = new TimeTask();
        temp.run();
    }
}

命令模式

定義命令介面,實現具體的命令,然後呼叫者,接收一個命令介面,使用者端傳入具體命令

// 命令介面
interface ICommand
{
    void Execute();
}

// 命令實現類
class OpenDocument: ICommand
{
    private Document doc;
    public OpenDocument(Document doc)
    {
        this.doc = doc;
    }
    public void Execute()
    {
        this.doc.Open();
    }
}

// 命令實現類
class CloseDocument : ICommand
{
    private Document doc;
    public CloseDocument(Document doc)
    {
        this.doc = doc;
    }
    public void Execute()
    {
        this.doc.Close();
    }
}

// 檔案類
class Document
{
    public void Open() { }
    public void Close() { }
}

// 使用者端使用
class Button
{
    private ICommand cmd;
    public void SetCommand(ICommand cmd)
    {
        this.cmd = cmd;
    }
    public void Click()
    {
        // 寫具體的業務
        cmd.Execute();
    }
}

class Client
{
    void main()
    {
        Document doc = new Document();
        ICommand cmd = new OpenDocument(doc);
        Button btn = new Button();
        btn.SetCommand(cmd);
        btn.Click();    // 開啟
    }
}

迭代器模式

迭代器模式,針對集合物件,將其封裝成可遍歷


// 迭代器介面
public interface IIterator<T>
{
    bool hasNext();
    T next();
}

// 集合介面
public interface ICollection<T>
{
    IIterator<T> CreateIterator();
}

// 集合類的實現
public class MyCollection<T> : ICollection<T>
{
    private List<T> items;
    public MyCollection()
    {
        items = new List<T>();// 初始化集合
    }
    public void Add(T data) {

        items.Add(data);
    }
    // 轉換成可迭代物件
    public IIterator<T> CreateIterator()
    {
        return new MyIterator<T>(items);
    }
}


// 迭代器的實現
public class MyIterator<T> : IIterator<T>
{
    private List<T> items;
    private int currentIndex;
    public MyIterator(List<T> items)
    {
        this.items = items;
        this.currentIndex = 0;
    }
    public bool hasNext()
    {
        return currentIndex < items.Count;
    }
    public T next()
    {
        T data = items[currentIndex];
        currentIndex++;
        return data;
    }
}

class Client
{
    void main() {
        MyCollection<string> arr = new MyCollection<string>();
        arr.Add("a");
        arr.Add("b");
        arr.Add("c");
        var iarr = arr.CreateIterator();
        while (iarr.hasNext())
        {
            Console.WriteLine(iarr.next() + "---");
        }
    }
}

觀察者模式

一對多關係,當一個物件的狀態發生了變化,其相關的依賴物件都能夠得到通知

// 主題介面
public interface ISubject
{
   void Attach(IObserver observer);
   void Detach(IObserver observer);
   void Notify();
}

// 觀察者介面
public interface IObserver
{
   void Update();
}

// 主題實現類
public class Subject : ISubject
{
   List<IObserver> observers = new List<IObserver>();
   public void Attach(IObserver observer)
   {
       observers.Add(observer);
   }

   public void Detach(IObserver observer)
   {
       observers.Remove(observer);
   }

   // 通知所有觀察者
   public void Notify()
   {
       foreach (var item in observers)
       {
           item.Update();
       }
   }
   public void SetTime()
   {
       Console.WriteLine("主題設定了時間");
       this.Notify();
   }
}

// 觀察者實現類
public class Observer : IObserver
{
   public void Update()
   {
       Console.WriteLine("+");
   }
}

// 使用者端
class Client
{
   void main() {
       Observer observer1 = new Observer();
       Observer observer2 = new Observer();

       Subject subject = new Subject();
       subject.Attach(observer1);
       subject.Attach(observer2);
       subject.SetTime(); // 會自動通知觀察者
   }
}

中介者模式

物件之間不直接通訊,而是通過中介者物件來進行通訊

// 中介者介面
public interface IChatRoom
{
    void SendMessage(User user,string msg);
}

// 中介者實現類
public class ChatRoom : IChatRoom
{
    List<User> users;
    public ChatRoom()
    {
        users = new List<User>();
    }
    public void SendMessage(User user, string msg)
    {
        foreach (var item in users)
        {
            if (item != user)
            {
                item.ReciveMessage(msg);
            }
        }
    }
    public void Add(User user) { 
        users.Add(user);
    }
}

// 使用者類
public class User
{
    public string Name { get; set; }
    public IChatRoom ChatRoom { get; set; } 
    public User(IChatRoom chatRoom,string Name)
    {
        this.Name = Name;
        this.ChatRoom = chatRoom;
    }
    public void SendMessage(string msg) {
        // 重點!!,通過中介者進行使用者互動
        ChatRoom.SendMessage(this, msg);
    }
    public void ReciveMessage(string msg) {
        Console.WriteLine("接受到訊息:"+msg);
    }
}

class Client
{
    void main()
    {
        ChatRoom room = new ChatRoom();
        User user1 = new User(room, "張三");
        User user2 = new User(room, "李四");
        User user3 = new User(room, "王五");

        room.Add(user1);
        room.Add(user2);
        room.Add(user3);
        user1.SendMessage("天氣不錯");
    }
}

狀態模式

將狀態封裝成獨立的一個類, 通過修改一個類的狀態,以實現不同的邏輯

// 編輯器狀態介面
public interface IEditorState
{
    void Edit();
    void Save();
}

/// <summary>
/// 編輯狀態
/// </summary>
public class EditEditorState : IEditorState
{
    public void Edit()
    {
        Console.WriteLine("編輯");
    }

    public void Save()
    {
        Console.WriteLine("編輯狀態 無法儲存");
    }
}

// 預覽狀態
public class ViewEditorState : IEditorState
{
    public void Edit()
    {
        Console.WriteLine("預覽狀態 無法修改");
    }

    public void Save()
    {
        Console.WriteLine("儲存");
    }
}


// 編輯器實現類
public class EditorState : IEditorState
{
    public IEditorState EditState { get; set; }

    // 重點 此方法更改狀態,以實現不同邏輯
    public EditorState()
    {
        this.EditState = new EditEditorState();
    }
    public void SetState(IEditorState EditState)
    {
        this.EditState = EditState;
    }

    public void Edit()
    {
        this.EditState.Edit();
    }

    public void Save()
    {
        this.EditState.Save();
    }
}

// 使用者端
class Client
{
    void main() {
        EditorState editor = new EditorState();
        editor.Edit();
        editor.Save();
        // 這裡切換狀態
        editor.SetState(new ViewEditorState());
        editor.Edit();
        editor.Save();
    }
}

策略模式

將一個類的具體演演算法,抽離出來成為策略,切換策略可以實現不同的業務

// 策略介面
public interface IDrawingStrategy
{
    void Draw();
}

// 實線策略
public class SolidLineDrawingStrategy : IDrawingStrategy
{
    public void Draw()
    {
        Console.WriteLine("繪製實線");
    }
}

// 虛線策略
public class DottedLineDrawingStrategy : IDrawingStrategy
{
    public void Draw()
    {
        Console.WriteLine("繪製虛線");
    }
}

// 繪製策略上下文
public class DrawingContext
{
    private IDrawingStrategy drawingStrategy;

    public void SetDrawingStrategy(IDrawingStrategy drawingStrategy)
    {
        this.drawingStrategy = drawingStrategy;
    }

    // 繪製
    public void Draw() {
        drawingStrategy.Draw();
    }
}

// 使用者端
class Client
{
    void main() {
        DrawingContext drawing = new DrawingContext();
        drawing.SetDrawingStrategy(new SolidLineDrawingStrategy());  // 更改策略
        drawing.Draw();

        drawing.SetDrawingStrategy(new DottedLineDrawingStrategy()); // 更改策略
        drawing.Draw();
    }
}

責任鏈模式

沿著處理鏈傳遞,直到有一個能處理為止

// 抽象責任鏈
public abstract class Handler
{
    protected Handler success;
    public void SetHandle(Handler success)
    {
        this.success = success;
    }
    public abstract void Request(int sum);
}

public class A : Handler
{
    public override void Request(int sum)
    {
        if(sum>=0 && sum <= 10)
        {
            Console.WriteLine("進入a");
        }else if (success != null)
        {
            // 傳遞給下一個
            success.Request(sum);
        }
    }
}

public class B : Handler
{
    public override void Request(int sum)
    {
        if (sum >10  && sum <= 20)
        {
            Console.WriteLine("進入b");
        }
        else if (success != null)
        {
            // 傳遞給下一個
            success.Request(sum);
        }
    }
}
public class C : Handler
{
    public override void Request(int sum)
    {
        if (sum > 20 && sum <= 30)
        {
            Console.WriteLine("進入c");
        }
        else if (success != null)
        {
            // 傳遞給下一個
            success.Request(sum);
        }
    }
}

// 使用者端
class Client
{
    void main() {

        A a = new A();
        B b = new B();
        C c = new C();

        a.SetHandle(b);
        b.SetHandle(c);
        a.Request(15);
    }
}

存取者模式

在不改變物件的結構,定義新的操作。元素裡面有一個方法來接受存取者,如此以後需要新的操作,只需要新增存取者類即可

ObjectStructure obj = new ObjectStructure();
ElementA a = new ElementA();
ElementB b = new ElementB();

VisitorA va = new VisitorA();
VisitorB vb = new VisitorB();

obj.Add(a);
obj.Add(b);

obj.show(va);
obj.show(vb);


// 存取者介面
public interface IVisitor
{
    void Visitor(IElement el);
}

// 具體存取者A
public class VisitorA : IVisitor
{
    public void Visitor(IElement el)
    {
        Console.WriteLine("存取者A進行存取");
    }
}

// 具體存取者B
public class VisitorB : IVisitor
{
    public void Visitor(IElement el)
    {
        Console.WriteLine("存取者B進行存取");
    }
}

// 元素抽象類
public abstract class IElement
{
    public abstract void Accept(IVisitor visitor);
}

// 具體元素類A
public class ElementA : IElement
{
    public override void Accept(IVisitor visitor)
    {
        visitor.Visitor(this);
    }
}

// 具體元素類B
public class ElementB: IElement
{
    public override void Accept(IVisitor visitor)
    {
        visitor.Visitor(this);
    }
}

// 定義一個結構
public class ObjectStructure{ 
    List<IElement> children;
    public ObjectStructure()
    {
        children = new List<IElement>();
    }
    public void Add(IElement element) {
        this.children.Add(element);
    }

    // 重點!,這裡將存取者傳遞進來,存取者執行裡面的邏輯
    public void show(IVisitor visitor) {

        foreach (var item in children)
        {
            item.Accept(visitor);
        }
    }
}

備忘錄模式

捕獲和恢復物件的狀態,同時保持物件的封裝性,對於實現復原,恢復或歷史記錄功能的應用程式非常有用


// 備忘錄
public class MemoInfo
{
    public string State { get; }
    public MemoInfo(string state)
    {
        this.State = state;
    }
}

// 操作物件
public class OriginMemo
{
    public string state;
    public string State
    {
        get
        {
            return this.state;
        }
        set
        {
            this.state = value;
            Console.WriteLine("設定成:"+this.state);
        }
    }

    public MemoInfo CreateMemoInfo() { 
        return new MemoInfo(State);
    }
    public void RestData(MemoInfo memoInfo) {

        this.state = memoInfo.State;
        Console.WriteLine("恢復成:"+this.state);
    }
}

// 管理類
public class ManagerMemo
{
    public MemoInfo Memo { get; set; }
}

class Client
{
    void main() {

        OriginMemo memo = new OriginMemo();
        memo.State = "狀態1";
        ManagerMemo manager = new ManagerMemo();
        manager.Memo = memo.CreateMemoInfo();	// 這裡保留原有物件
        memo.State = "狀態2";
        memo.RestData(manager.Memo);	// 這裡進行恢復
    }
}

直譯器模式

定義語言文法,並解釋該語言的表示式

// 表示式類
public interface IExpression
{
    int Interpret();
}

// 加法表示式類
public class AddExpression : IExpression
{
    private readonly IExpression left;
    private readonly IExpression right;

    public AddExpression(IExpression left,IExpression right)
    {
        this.left = left;
        this.right = right;
    }
    public int Interpret()
    {
        return left.Interpret() + right.Interpret();
    }
}

// 數位類
public class NumberExpression : IExpression
{
    private int number;

    public NumberExpression(int number = 0)
    {
        this.number = number;
    }
    public int Interpret()
    {
        return number;
    }
}

// 使用者端
class Client
{
    void main() {

        IExpression a1 = new NumberExpression(1);
        IExpression a2 = new NumberExpression(3);

        IExpression a3 = new AddExpression(a1, a2);
        Console.WriteLine(a3.Interpret());
    }
}