知識點來源:人間自有韜哥在,豆包
目錄
- 一、七大原則
- 1. 單一職責原則 (Single Responsibility Principle)
- 2. 開放封閉原則 (Open-Closed Principle)
- 3. 里氏替換原則 (Liskov Substitution Principle)
- 4. 接口隔離原則 (Interface Segregation Principle)
- 5. 依賴倒轉原則 (Dependency Inversion Principle)
- 6. 合成復用原則 (Composite Reuse Principle)
- 7. 迪米特法則 (Law of Demeter)
- 二、設計模式
- 2.1. 創建型模式
- 2.1.1單例模式(Singleton Pattern)
- 2.1.2.簡單工廠模式(Simple Factory Pattern)
- 2.1.3.工廠方法模式(Factory Method Pattern)
- 2.1.4 抽象工廠模式(Abstract Factory Pattern)
- 2.1.5.原型模式(Prototype Pattern)
- 2.1.6.建造者模式(Builder Pattern)
- 2.2. 結構型模式
- 2.2.1. 外觀模式(Facade Pattern)
- 2.2.2. 適配器模式(Adapter Pattern)
- 2.2.3. 代理模式(Proxy Pattern)
- 2.2.4. 組合模式(Composite Pattern)
- 2.2.5. 橋接模式(Bridge Pattern)
- 2.2.6. 裝飾模式(Decorator Pattern)
- 2.2.7. 享元模式(Flyweight Pattern)
- 2.3. 行為型模式
- 2.3.1. 策略模式(Strategy Pattern)
- 2.3.2. 觀察者模式(Observer Pattern)
- 2.3.3. 迭代器模式(Iterator Pattern)
- 2.3.4. 模板方法模式(Template Method Pattern)
- 2.3.5. 命令模式(Command Pattern)
- 2.3.6. 狀態模式(State Pattern)
- 2.3.7. 備忘錄模式(Memento Pattern)
- 2.3.8. 職責鏈模式(Chain of Responsibility Pattern)
- 2.3.9. 中介者模式(Mediator Pattern)
- 2.3.10. 訪問者模式(Visitor Pattern)
- 2.3.11. 解釋器模式(Interpreter Pattern)
一、七大原則
1. 單一職責原則 (Single Responsibility Principle)
- 定義:單一職責原則 (Single Responsibility Principle - SRP):一個類應該只有一個修改的理由。這意味著一個類應該只有一個單一的責任,不涉及多個不相關的功能或任務。這有助于使類更加可維護和易于理解。
- 示例:在一個游戲開發中,有一個
Player
類,如果這個類既負責處理玩家的移動邏輯,又負責處理玩家的戰斗邏輯,那么當游戲的移動規則或者戰斗規則發生變化時,都需要修改Player
類。這就違反了單一職責原則。更好的做法是將移動邏輯和戰斗邏輯分別封裝到不同的類中,比如PlayerMovement
類和PlayerCombat
類,這樣當移動規則變化時,只需要修改PlayerMovement
類,而不會影響到PlayerCombat
類,反之亦然。
2. 開放封閉原則 (Open-Closed Principle)
- 定義:開放封閉原則 (Open-Closed Principle - OCP):軟件實體(類、模塊、函數等)應該對擴展開放,但對修改關閉。這意味著可以通過擴展現有代碼來添加新功能,而不需要修改已有的代碼。
- 示例:在一個游戲中,有一個
Enemy
類表示敵人,現在游戲要增加一種新的敵人類型,具有特殊的行為。如果按照開放封閉原則,我們不應該直接修改Enemy
類的代碼,而是應該創建一個新的類,繼承自Enemy
類,并在新類中實現特殊的行為。這樣,既增加了新功能,又沒有修改原有的Enemy
類代碼,避免了對原有代碼的影響,降低了引入新 bug 的風險。
3. 里氏替換原則 (Liskov Substitution Principle)
- 定義:里氏替換原則 (Liskov Substitution Principle - LSP):子類型(派生類或子類)必須能夠替換其基類型(父類或超類)而不影響程序的正確性。這確保了繼承關系的正確性和一致性。
- 示例:在一個游戲中有一個
Shape
類表示形狀,有Rectangle
(矩形)和Square
(正方形)類繼承自Shape
類。如果在游戲中某個地方使用了Shape
類的對象來計算面積,那么當我們用Rectangle
或Square
類的對象替換Shape
類的對象時,計算面積的功能應該能夠正確執行,而不會出現錯誤或異常。這是因為Rectangle
和Square
類都遵循了Shape
類的契約,實現了計算面積的方法,并且保證了方法的行為符合父類的預期。
4. 接口隔離原則 (Interface Segregation Principle)
- 定義:接口隔離原則 (Interface Segregation Principle - ISP):不應該強迫一個類實現它不需要的接口。這個原則鼓勵創建小而專注的接口,以便類只需實現其所需的功能。
- 示例:在一個游戲開發中,有一個
Character
接口,其中包含了Move
(移動)、Attack
(攻擊)、Defend
(防御)和Fly
(飛行)等方法。現在有一個Warrior
類(戰士)和一個Wizard
類(巫師),戰士可以移動、攻擊和防御,但不能飛行,巫師可以移動、攻擊和飛行,但不需要防御。按照接口隔離原則,我們不應該讓Warrior
類和Wizard
類都實現整個Character
接口,而是應該將Character
接口拆分成更小的接口,比如IMovable
(可移動)、IAttackable
(可攻擊)、IDefendable
(可防御)和IFlyable
(可飛行)接口,然后讓Warrior
類實現IMovable
、IAttackable
和IDefendable
接口,Wizard
類實現IMovable
、IAttackable
和IFlyable
接口。這樣,每個類只依賴于它需要的接口,降低了類之間的耦合度。
5. 依賴倒轉原則 (Dependency Inversion Principle)
- 定義:依賴倒轉原則 (Dependency Inversion Principle - DIP):高層模塊不應該依賴于低層模塊,兩者都應該依賴于抽象。此原則還強調了抽象不應該依賴于細節,細節應該依賴于抽象。
- 示例:在一個游戲中,有一個
GameManager
類(高層模塊)負責管理游戲的流程,它需要使用到Player
類(低層模塊)和Enemy
類(低層模塊)。如果GameManager
類直接依賴于Player
類和Enemy
類的具體實現,那么當Player
類或Enemy
類的實現發生變化時,GameManager
類也需要相應地修改。為了遵循依賴倒轉原則,我們可以定義一個抽象的ICharacter
接口,讓Player
類和Enemy
類都實現這個接口,然后讓GameManager
類依賴于ICharacter
接口。這樣,當Player
類或Enemy
類的實現發生變化時,只要它們仍然實現了ICharacter
接口,GameManager
類就不需要修改,提高了代碼的穩定性和可維護性。
6. 合成復用原則 (Composite Reuse Principle)
- 定義:組合復用原則 (Composite Reuse Principle - CRP):應該優先使用組合(組合多個小的、獨立的組件)而不是繼承來實現代碼復用。這鼓勵更靈活的代碼結構,以減少類之間的緊耦合。
- 示例:在一個游戲中,有一個
Weapon
類表示武器,有不同類型的武器,如Sword
(劍)、Bow
(弓)等。如果我們使用繼承來實現不同類型的武器,那么每個武器類都需要繼承Weapon
類,并可能重寫一些方法。但是,如果我們使用組合復用原則,我們可以將武器的公共行為封裝到一個WeaponBehavior
類中,然后讓Sword
類和Bow
類包含一個WeaponBehavior
類的實例,通過委托的方式來調用WeaponBehavior
類的方法。這樣,當我們需要增加新的武器類型時,只需要創建一個新的類,并組合一個WeaponBehavior
類的實例,而不需要修改現有的武器類,提高了代碼的復用性和可擴展性。
7. 迪米特法則 (Law of Demeter)
- 定義:迪米特法則 (Law of Demeter - LoD):也稱為最小知道原則,一個對象應該對其他對象有盡可能少的了解,只與其直接的朋友交互。這有助于減少類之間的依賴關系,提高系統的松散耦合性。
- 示例:在一個游戲中,有一個
Player
類和一個Inventory
類(背包),Player
類需要獲取背包中的物品信息。如果Player
類直接訪問Inventory
類的內部數據結構來獲取物品信息,那么Player
類就對Inventory
類的內部細節了解得太多了。按照迪米特法則,Inventory
類應該提供一些公共的方法來獲取物品信息,而Player
類只需要調用這些方法,而不應該直接訪問Inventory
類的內部數據結構。這樣,降低了Player
類和Inventory
類之間的耦合度,提高了代碼的可維護性和可擴展性。
二、設計模式
2.1. 創建型模式
創建型模式主要用于對象的創建過程,它將對象的創建和使用分離,使得代碼更加靈活、可維護和可擴展。以下是幾種常見的創建型模式:
2.1.1單例模式(Singleton Pattern)
-
定義:確保一個類只有一個實例,并提供一個全局訪問點。
-
示例場景:在游戲開發中,游戲的配置信息通常只需要一個實例來管理,比如游戲的音量設置、分辨率設置等。使用單例模式可以保證這些配置信息在整個游戲中只有一個實例,避免出現多個實例導致的配置沖突問題。
-
代碼示例(C#):
public class GameConfig
{private static GameConfig instance;private GameConfig() { }public static GameConfig Instance{get{if (instance == null){instance = new GameConfig();}return instance;}}public int Volume { get; set; }public int Resolution { get; set; }
}
2.1.2.簡單工廠模式(Simple Factory Pattern)
- 定義:提供了一個單獨的工廠類,該工廠類用于根據客戶端的請求來創建不同類型的對象,而客戶端無需了解對象的創建過程。
- 示例場景:在游戲開發中,有不同類型的武器,如劍、弓等。使用簡單工廠模式可以根據玩家的選擇創建不同類型的武器,而不需要在玩家代碼中直接使用 new 關鍵字創建武器對象,提高了代碼的可維護性和可擴展性。
- 代碼示例(C#):
// 抽象武器類
public abstract class Weapon
{public abstract void Use();
}// 劍類
public class Sword : Weapon
{public override void Use(){Console.WriteLine("使用劍進行攻擊");}
}// 弓類
public class Bow : Weapon
{public override void Use(){Console.WriteLine("使用弓進行射擊");}
}// 簡單武器工廠類
public class WeaponFactory
{public static Weapon CreateWeapon(string weaponType){switch (weaponType){case "Sword":return new Sword();case "Bow":return new Bow();default:throw new ArgumentException("不支持的武器類型");}}
}class Program
{static void Main(){// 使用簡單工廠創建劍Weapon sword = WeaponFactory.CreateWeapon("Sword");sword.Use();// 使用簡單工廠創建弓Weapon bow = WeaponFactory.CreateWeapon("Bow");bow.Use();}
}
2.1.3.工廠方法模式(Factory Method Pattern)
-
定義:定義一個用于創建對象的接口,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。
-
示例場景:在游戲中,有不同類型的敵人,如近戰敵人、遠程敵人等。使用工廠模式可以根據不同的條件創建不同類型的敵人,而不需要在代碼中直接使用
new
關鍵字創建敵人對象,提高了代碼的可維護性和可擴展性。 -
代碼示例(C#):
// 抽象敵人類
public abstract class Enemy
{public abstract void Attack();
}// 近戰敵人類
public class MeleeEnemy : Enemy
{public override void Attack(){Console.WriteLine("近戰敵人攻擊");}
}// 遠程敵人類
public class RangedEnemy : Enemy
{public override void Attack(){Console.WriteLine("遠程敵人攻擊");}
}// 抽象工廠類
public abstract class EnemyFactory
{public abstract Enemy CreateEnemy();
}// 近戰敵人工廠類
public class MeleeEnemyFactory : EnemyFactory
{public override Enemy CreateEnemy(){return new MeleeEnemy();}
}// 遠程敵人工廠類
public class RangedEnemyFactory : EnemyFactory
{public override Enemy CreateEnemy(){return new RangedEnemy();}
}class Program
{static void Main(){// 創建近戰敵人工廠EnemyFactory meleeFactory = new MeleeEnemyFactory();Enemy meleeEnemy = meleeFactory.CreateEnemy();meleeEnemy.Attack();// 創建遠程敵人工廠EnemyFactory rangedFactory = new RangedEnemyFactory();Enemy rangedEnemy = rangedFactory.CreateEnemy();rangedEnemy.Attack();}
}
2.1.4 抽象工廠模式(Abstract Factory Pattern)
-
定義:提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。
-
示例場景:在游戲開發中,不同的游戲關卡可能需要不同風格的道具和敵人。使用抽象工廠模式可以創建一個抽象工廠接口,然后為每個關卡實現一個具體的工廠類,每個工廠類可以創建該關卡所需的道具和敵人。
-
代碼示例(C#):
// 道具抽象類
public abstract class Item
{public abstract void Use();
}// 敵人抽象類
public abstract class Enemy
{public abstract void Attack();
}// 抽象工廠接口
public interface IGameFactory
{Item CreateItem();Enemy CreateEnemy();
}// 第一關工廠類
public class Level1Factory : IGameFactory
{public Item CreateItem(){return new Level1Item();}public Enemy CreateEnemy(){return new Level1Enemy();}
}// 第一關道具類
public class Level1Item : Item
{public override void Use(){Console.WriteLine("使用第一關道具");}
}// 第一關敵人類
public class Level1Enemy : Enemy
{public override void Attack(){Console.WriteLine("第一關敵人攻擊");}
}
-
總結
-
簡單工廠模式通過一個單一的工廠類,依據傳入的條件創建不同類型的產品對象。該工廠類集中了所有產品的創建邏輯,客戶端只需調用工廠類的創建方法并傳入相關條件,即可獲取所需產品,無需關心產品的具體創建過程。
-
工廠模式則定義了一個創建對象的抽象接口,將對象的創建邏輯延遲到具體的子類工廠中。每個具體工廠類負責創建一種特定類型的產品,客戶端通過選擇不同的具體工廠類來創建相應的產品,相比簡單工廠模式,更符合開閉原則,增強了代碼的可擴展性。
-
抽象工廠模式中,每個具體工廠類負責創建一系列相關的產品對象。這些產品對象通常屬于同一產品族,它們之間存在某種內在聯系。客戶端通過選擇合適的具體工廠類,能夠一次性創建出一系列相互匹配的產品,為構建復雜系統提供了便利,適用于需要創建多種相關產品且產品族結構較為固定的場景。
2.1.5.原型模式(Prototype Pattern)
-
定義:用原型實例指定創建對象的種類,并且通過復制這些原型創建新的對象。
-
示例場景:在游戲開發中,存在大量相同類型的游戲角色或道具。例如,游戲中有一群相同外觀和屬性的小兵,若每次創建小兵都進行初始化操作會消耗大量資源和時間。此時可以使用原型模式,先創建一個小兵原型,后續通過克隆該原型來快速創建新的小兵對象。
-
代碼示例(C#):
// 定義原型接口
public interface IPrototype<T>
{T Clone();
}// 小兵類,實現原型接口
public class Soldier : IPrototype<Soldier>
{public string Name { get; set; }public int Health { get; set; }public int Attack { get; set; }public Soldier(string name, int health, int attack){Name = name;Health = health;Attack = attack;}public Soldier Clone(){// 淺克隆,對于值類型成員會復制值,引用類型成員會復制引用// 深度拷貝需要把值傳過去創建一個新類return (Soldier)this.MemberwiseClone();}
}class Program
{static void Main(){// 創建一個小兵原型Soldier prototypeSoldier = new Soldier("小兵1", 100, 20);// 克隆一個新的小兵Soldier clonedSoldier = prototypeSoldier.Clone();Console.WriteLine($"克隆小兵的名稱: {clonedSoldier.Name}, 生命值: {clonedSoldier.Health}, 攻擊力: {clonedSoldier.Attack}");}
}
- 總結:原型模式借助復制原型實例創建新對象,降低復雜對象創建開銷,提升性能。它把對象創建邏輯封裝在原型類中,客戶端只需調用克隆方法,讓代碼創建部分更簡潔,利于維護與復用,且能靈活應對不同場景下對象創建需求。
2.1.6.建造者模式(Builder Pattern)
-
定義:建造者模式(Builder Pattern)將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
-
示例場景:在游戲開發中,創建不同風格的游戲場景,如森林場景、沙漠場景等。每個場景都包含地形、建筑、植被等多個元素,且不同風格的場景這些元素的具體表現不同。使用建造者模式,我們可以定義一個場景建造者接口,然后為不同風格的場景實現具體的建造者類,通過指揮者來調用建造者的方法構建出完整的場景。
-
代碼示例(C#):
// 游戲場景類
public class GameScene
{public string Terrain { get; set; }public string Buildings { get; set; }public string Vegetation { get; set; }public override string ToString(){return $"地形: {Terrain}, 建筑: {Buildings}, 植被: {Vegetation}";}
}// 場景建造者接口
public interface ISceneBuilder
{void BuildTerrain();void BuildBuildings();void BuildVegetation();GameScene GetScene();
}// 森林場景建造者
public class ForestSceneBuilder : ISceneBuilder
{private GameScene scene = new GameScene();public void BuildTerrain(){scene.Terrain = "草地和泥土";}public void BuildBuildings(){scene.Buildings = "木屋和樹屋";}public void BuildVegetation(){scene.Vegetation = "樹木和花草";}public GameScene GetScene(){return scene;}
}// 沙漠場景建造者
public class DesertSceneBuilder : ISceneBuilder
{private GameScene scene = new GameScene();public void BuildTerrain(){scene.Terrain = "沙地";}public void BuildBuildings(){scene.Buildings = "金字塔和帳篷";}public void BuildVegetation(){scene.Vegetation = "仙人掌";}public GameScene GetScene(){return scene;}
}// 指揮者類
public class SceneDirector
{private ISceneBuilder builder;public SceneDirector(ISceneBuilder builder){this.builder = builder;}public GameScene ConstructScene(){builder.BuildTerrain();builder.BuildBuildings();builder.BuildVegetation();return builder.GetScene();}
}class Program
{static void Main(){// 創建森林場景建造者ISceneBuilder forestBuilder = new ForestSceneBuilder();SceneDirector forestDirector = new SceneDirector(forestBuilder);GameScene forestScene = forestDirector.ConstructScene();Console.WriteLine("森林場景: " + forestScene);// 創建沙漠場景建造者ISceneBuilder desertBuilder = new DesertSceneBuilder();SceneDirector desertDirector = new SceneDirector(desertBuilder);GameScene desertScene = desertDirector.ConstructScene();Console.WriteLine("沙漠場景: " + desertScene);}
}
- 總結:建造者模式分離復雜對象構建和表示,客戶端只需告知類型與內容,構建細節由建造者處理。它統一構建流程,方便根據需求切換建造者,增強系統擴展性,使復雜對象創建過程更清晰可控,提升代碼可維護性。
2.2. 結構型模式
2.2.1. 外觀模式(Facade Pattern)
-
定義:為子系統中的一組接口提供一個一致的界面,此模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。它隱藏了系統的復雜性,將多個復雜的子系統操作封裝在一個簡單的接口中,讓客戶端只需要與這個外觀類交互,而無需了解子系統的內部細節。
-
示例場景:在游戲開發中,一個游戲的啟動過程涉及到資源加載、場景初始化、音效初始化、網絡連接初始化等多個復雜的子系統操作。通過外觀模式,可以創建一個
GameFacade
類,將這些操作封裝在一個StartGame
方法中,游戲啟動時,開發者只需調用GameFacade.StartGame
方法,而不需要分別調用各個子系統的初始化方法。 -
代碼示例(C#):
// 資源加載子系統
public class ResourceLoader
{public void LoadResources(){Console.WriteLine("加載游戲資源");}
}// 場景初始化子系統
public class SceneInitializer
{public void InitializeScene(){Console.WriteLine("初始化游戲場景");}
}// 音效初始化子系統
public class SoundInitializer
{public void InitializeSound(){Console.WriteLine("初始化音效系統");}
}// 網絡連接初始化子系統
public class NetworkInitializer
{public void InitializeNetwork(){Console.WriteLine("初始化網絡連接");}
}// 外觀類
public class GameFacade
{private ResourceLoader resourceLoader;private SceneInitializer sceneInitializer;private SoundInitializer soundInitializer;private NetworkInitializer networkInitializer;public GameFacade(){resourceLoader = new ResourceLoader();sceneInitializer = new SceneInitializer();soundInitializer = new SoundInitializer();networkInitializer = new NetworkInitializer();}public void StartGame(){resourceLoader.LoadResources();sceneInitializer.InitializeScene();soundInitializer.InitializeSound();networkInitializer.InitializeNetwork();}}
class Program
{static void Main(){// 創建 GameFacade 實例GameFacade gameFacade = new GameFacade();// 啟動游戲gameFacade.StartGame();}
}
- 總結:外觀模式通過提供一個統一的接口,簡化了客戶端與復雜子系統之間的交互,提高了代碼的可維護性和可復用性。它將子系統的變化封裝在外觀類內部,對客戶端透明,使得客戶端代碼更加簡潔和易于理解。
2.2.2. 適配器模式(Adapter Pattern)
-
定義:將一個類的接口轉換成客戶希望的另外一個接口。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。它通過創建一個適配器類,在適配器類中對現有類的接口進行轉換,以滿足目標接口的需求。
-
示例場景:在游戲開發中,引入了一個第三方的物理引擎庫,該庫提供的碰撞檢測接口與游戲現有代碼中的接口不兼容。為了能夠在游戲中使用這個物理引擎的碰撞檢測功能,可以創建一個適配器類,將物理引擎的碰撞檢測接口適配成游戲代碼能夠使用的接口。
-
代碼示例(C#):
// 目標接口
public interface ICollisionDetector
{void DetectCollision();
}// 第三方物理引擎的碰撞檢測類
public class ThirdPartyCollisionDetector
{public void CheckCollision(){Console.WriteLine("第三方物理引擎檢測碰撞");}
}// 適配器類
public class CollisionDetectorAdapter : ICollisionDetector
{private ThirdPartyCollisionDetector thirdPartyDetector;public CollisionDetectorAdapter(){thirdPartyDetector = new ThirdPartyCollisionDetector();}public void DetectCollision(){thirdPartyDetector.CheckCollision();}
}
class Program
{static void Main(){// 創建適配器實例ICollisionDetector detector = new CollisionDetectorAdapter();// 調用接口方法,實際上會調用第三方物理引擎的檢測方法detector.DetectCollision();}
}
- 總結:適配器模式解決了接口不兼容的問題,使得不同接口的類能夠協同工作。它在不修改現有類代碼的情況下,通過適配器類進行接口轉換,提高了代碼的可擴展性和復用性,尤其適用于整合不同的第三方庫或系統。
2.2.3. 代理模式(Proxy Pattern)
-
定義:為其他對象提供一種代理以控制對這個對象的訪問。代理對象在客戶端和目標對象之間起到中介作用,它可以在訪問目標對象前后執行一些額外的操作,比如權限驗證、緩存處理、延遲加載等。
-
示例場景:在游戲中,有些資源(如大型的紋理、模型等)加載比較耗時,為了避免在需要使用這些資源時才開始加載導致游戲卡頓,可以使用代理模式。在游戲啟動時,先創建一個代理對象,當真正需要使用資源時,代理對象再去加載實際的資源。
-
代碼示例(C#):
// 資源接口
public interface IResource
{void Load();
}// 實際資源類
public class RealResource : IResource
{public void Load(){Console.WriteLine("加載實際資源");}
}// 代理資源類
public class ProxyResource : IResource
{private RealResource realResource;public void Load(){if (realResource == null){realResource = new RealResource();}realResource.Load();}
}
class Program
{static void Main (){
// 創建代理資源實例IResource resource = new ProxyResource ();
// 調用代理資源的 Load 方法resource.Load ();}
}
- 總結:代理模式通過代理對象對目標對象的訪問進行控制,增加了系統的靈活性和可擴展性。它可以在不改變目標對象的基礎上,為其添加額外的功能,適用于需要對對象訪問進行控制、優化或增強的場景。
2.2.4. 組合模式(Composite Pattern)
-
定義:將對象組合成樹形結構以表示“部分 - 整體”的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性,即客戶端可以統一地對待組合對象和單個對象。它通過定義一個抽象組件類,具體組件類可以是葉子節點(單個對象)或組合節點(包含多個對象),從而構建出樹形結構。
-
示例場景:在游戲場景中,一個場景由多個游戲對象組成,這些游戲對象可以是單個的角色、道具,也可以是由多個角色和道具組成的小組。使用組合模式,可以將這些游戲對象統一管理,方便對整個場景或其中的部分進行操作,比如統一移動、刪除等。
-
代碼示例(C#):
// 抽象游戲對象類
public abstract class GameObject
{public string Name { get; set; }public abstract void Move();public virtual void Add(GameObject gameObject){throw new NotImplementedException();}public virtual void Remove(GameObject gameObject){throw new NotImplementedException();}
}// 葉子節點:單個角色類
public class Character : GameObject
{public override void Move(){Console.WriteLine($"{Name} 角色移動");}
}// 組合節點:游戲對象小組類
public class GameObjectGroup : GameObject
{private List<GameObject> children = new List<GameObject>();public override void Move(){foreach (var child in children){child.Move();}}public override void Add(GameObject gameObject){children.Add(gameObject);}public override void Remove(GameObject gameObject){children.Remove(gameObject);}
}
class Program
{static void Main(){// 創建角色Character character1 = new Character { Name = "角色1" };Character character2 = new Character { Name = "角色2" };// 創建游戲對象小組GameObjectGroup group = new GameObjectGroup { Name = "小組" };// 將角色添加到小組中group.Add(character1);group.Add(character2);// 讓小組移動,會觸發小組內所有角色移動group.Move();// 從小組中移除一個角色group.Remove(character1);// 再次讓小組移動group.Move();}
}
- 總結:組合模式簡化了樹形結構的操作,使得客戶端可以統一處理單個對象和組合對象,提高了代碼的可維護性和可擴展性。它適用于需要處理具有層次結構的數據或對象的場景,能夠有效地管理和操作復雜的對象組合。
2.2.5. 橋接模式(Bridge Pattern)
-
定義:將抽象部分與它的實現部分分離,使它們都可以獨立地變化。它通過將抽象和實現解耦,使得它們可以沿著各自的維度進行變化,從而提高系統的靈活性和可擴展性。具體來說,抽象類依賴于一個實現類接口,而不是具體的實現類,這樣可以在運行時動態地切換實現類。
-
示例場景:在游戲開發中,有不同類型的游戲角色(如戰士、法師),每個角色又有不同的武器(如劍、法杖)。使用橋接模式,可以將角色類型和武器類型分離,使得不同的角色可以搭配不同的武器,并且在添加新的角色類型或武器類型時,不會影響到對方。
-
代碼示例(C#):
// 武器接口
public interface IWeapon
{void Use();
}// 劍類
public class Sword : IWeapon
{public void Use(){Console.WriteLine("使用劍");}
}// 法杖類
public class Staff : IWeapon
{public void Use(){Console.WriteLine("使用法杖");}
}// 抽象角色類
public abstract class Character
{protected IWeapon weapon;public Character(IWeapon weapon){this.weapon = weapon;}public abstract void Attack();
}// 戰士類
public class Warrior : Character
{public Warrior(IWeapon weapon) : base(weapon) { }public override void Attack(){Console.WriteLine("戰士攻擊");weapon.Use();}
}// 法師類
public class Mage : Character
{public Mage(IWeapon weapon) : base(weapon) { }public override void Attack(){Console.WriteLine("法師攻擊");weapon.Use();}
}
class Program
{static void Main(){// 創建武器IWeapon sword = new Sword();IWeapon staff = new Staff();// 創建戰士并使用劍進行攻擊Character warrior = new Warrior(sword);warrior.Attack();// 創建法師并使用法杖進行攻擊Character mage = new Mage(staff);mage.Attack();// 讓戰士切換到法杖進行攻擊warrior = new Warrior(staff);warrior.Attack();}
}
- 總結:橋接模式通過解耦抽象和實現,使得系統更加靈活,能夠應對不斷變化的需求。它適用于需要將多個維度的變化進行分離的場景,避免了在多個維度組合時導致的類爆炸問題,提高了代碼的可維護性和可復用性。
2.2.6. 裝飾模式(Decorator Pattern)
-
定義:動態地給一個對象添加一些額外的職責。就增加功能來說,裝飾器模式比生成子類更為靈活。它通過創建一個裝飾器類,該類繼承自抽象組件類,并且包含一個對抽象組件類的引用,在裝飾器類中可以添加額外的功能,并調用被裝飾對象的方法。
-
示例場景:在游戲中,角色可以裝備不同的武器和防具,每種武器和防具都可以增加角色的攻擊力、防御力等屬性。使用裝飾模式可以在不改變角色類的基礎上,動態地為角色添加不同的武器和防具。
-
代碼示例(C#):
// 角色抽象類
public abstract class Character
{public abstract int GetAttack();public abstract int GetDefense();
}// 具體角色類
public class Player : Character
{public override int GetAttack(){return 10;}public override int GetDefense(){return 5;}
}// 裝飾器抽象類
public abstract class CharacterDecorator : Character
{protected Character character;public CharacterDecorator(Character character){this.character = character;}
}// 武器裝飾器類
public class WeaponDecorator : CharacterDecorator
{public WeaponDecorator(Character character) : base(character) { }public override int GetAttack(){return character.GetAttack() + 20;}public override int GetDefense(){return character.GetDefense();}
}// 防具裝飾器類
public class ArmorDecorator : CharacterDecorator
{public ArmorDecorator(Character character) : base(character) { }public override int GetAttack(){return character.GetAttack();}public override int GetDefense(){return character.GetDefense() + 15;}
}
class Program
{static void Main(){// 創建一個玩家角色Character player = new Player();// 輸出原始角色的攻擊和防御屬性Console.WriteLine($"原始角色 - 攻擊: {player.GetAttack()}, 防御: {player.GetDefense()}");// 給角色裝備武器player = new WeaponDecorator(player);Console.WriteLine($"裝備武器后 - 攻擊: {player.GetAttack()}, 防御: {player.GetDefense()}");// 給角色裝備防具player = new ArmorDecorator(player);Console.WriteLine($"裝備武器和防具后 - 攻擊: {player.GetAttack()}, 防御: {player.GetDefense()}");}
}
- 總結:裝飾模式通過動態地為對象添加功能,避免了大量子類的創建,提高了代碼的可維護性和可擴展性。它適用于需要在運行時為對象添加不同功能的場景,使得代碼更加簡潔和靈活。
2.2.7. 享元模式(Flyweight Pattern)
-
定義:運用共享技術有效地支持大量細粒度的對象。它通過共享已經存在的對象來減少對象的創建,從而降低內存消耗和提高性能。享元對象通常是不可變的,并且被多個客戶端共享使用。
-
示例場景:在游戲中,有大量的小型游戲對象,如草叢、石頭等,這些對象具有相同的外觀和基本屬性。使用享元模式,可以創建少量的享元對象,然后在不同的位置復用這些對象,而不是為每個對象都創建一個獨立的實例。
-
代碼示例(C#):
// 享元工廠類
public class FlyweightFactory
{private Dictionary<string, IGameItem> flyweights = new Dictionary<string, IGameItem>();public IGameItem GetFlyweight(string key){if (!flyweights.ContainsKey(key)){flyweights.Add(key, new Grass());}return flyweights[key];}
}// 抽象享元類
public interface IGameItem
{void Display(Vector2 position);
}// 具體享元類:草叢
public class Grass : IGameItem
{public void Display(Vector2 position){Console.WriteLine($"在位置 {position} 顯示草叢");}
}// 位置結構體
public struct Vector2
{public float X { get; set; }public float Y { get; set; }public Vector2(float x, float y){X = x;Y = y;}
}
class Program
{static void Main(){// 創建享元工廠FlyweightFactory factory = new FlyweightFactory();// 定義一些位置Vector2 position1 = new Vector2(10, 20);Vector2 position2 = new Vector2(30, 40);// 從工廠獲取草叢享元并在不同位置顯示IGameItem grass1 = factory.GetFlyweight("grass");grass1.Display(position1);IGameItem grass2 = factory.GetFlyweight("grass");grass2.Display(position2);// 驗證是否為同一對象Console.WriteLine($"grass1 和 grass2 是否為同一對象: {ReferenceEquals(grass1, grass2)}");}
}
- 總結:享元模式通過對象共享,減少了內存占用和對象創建的開銷,提高了系統的性能。它適用于存在大量相似對象的場景,通過共享對象的不變部分,提高了資源的利用率。但需要注意的是,使用享元模式時,對象的狀態需要進行合理的分離,可變狀態應由外部環境來維護,以確保共享對象的正確性。
2.3. 行為型模式
2.3.1. 策略模式(Strategy Pattern)
-
定義:定義一系列的算法,把它們一個個封裝起來,并且使它們可相互替換。策略模式讓算法的變化獨立于使用算法的客戶。通過將不同的算法封裝成獨立的策略類,客戶端可以根據不同的需求選擇不同的策略,從而實現算法的動態切換。
-
示例場景:在游戲中,角色的攻擊方式多種多樣,如近戰攻擊、遠程攻擊、魔法攻擊等。使用策略模式,可以將每種攻擊方式封裝成一個策略類,角色根據不同的戰斗場景和目標選擇合適的攻擊策略。例如,在與近戰敵人戰斗時,角色選擇近戰攻擊策略;在面對遠程敵人時,選擇遠程攻擊策略。
-
代碼示例(C#):
// 攻擊策略接口
public interface IAttackStrategy
{void Attack();
}// 近戰攻擊策略類
public class MeleeAttackStrategy : IAttackStrategy
{public void Attack(){Console.WriteLine("進行近戰攻擊");}
}// 遠程攻擊策略類
public class RangedAttackStrategy : IAttackStrategy
{public void Attack(){Console.WriteLine("進行遠程攻擊");}
}// 角色類
public class Character
{private IAttackStrategy attackStrategy;public Character(IAttackStrategy attackStrategy){this.attackStrategy = attackStrategy;}public void SetAttackStrategy(IAttackStrategy attackStrategy){this.attackStrategy = attackStrategy;}public void PerformAttack(){attackStrategy.Attack();}
}
class Program
{static void Main(){// 創建近戰攻擊策略IAttackStrategy meleeStrategy = new MeleeAttackStrategy();// 創建角色并使用近戰攻擊策略Character character = new Character(meleeStrategy);// 執行攻擊character.PerformAttack();// 創建遠程攻擊策略IAttackStrategy rangedStrategy = new RangedAttackStrategy();// 為角色設置遠程攻擊策略character.SetAttackStrategy(rangedStrategy);// 再次執行攻擊character.PerformAttack();}
}
- 總結:策略模式提高了算法的靈活性和可維護性,將算法的選擇和實現分離,使得代碼更加清晰。它適用于多種算法可供選擇且需要動態切換算法的場景,通過使用策略模式,可以避免大量的條件判斷語句,使代碼更易于擴展和維護。
2.3.2. 觀察者模式(Observer Pattern)
-
定義:定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴它的對象都會得到通知并自動更新。被觀察的對象稱為主題(Subject),依賴主題的對象稱為觀察者(Observer)。主題維護一個觀察者列表,當主題狀態變化時,會遍歷列表通知所有觀察者。
-
示例場景:在游戲中,玩家的生命值、金幣數量等狀態變化時,游戲界面上的相關顯示組件(如生命值條、金幣數量顯示框)需要實時更新。使用觀察者模式,玩家對象作為主題,相關顯示組件作為觀察者,當玩家狀態改變時,自動通知并更新顯示組件。
-
代碼示例(C#):
// 觀察者接口
public interface IObserver
{void Update(int value);
}// 主題接口
public interface ISubject
{void Attach(IObserver observer);void Detach(IObserver observer);void Notify();
}// 具體主題類
public class PlayerStatus : ISubject
{private List<IObserver> observers = new List<IObserver>();private int health;public int Health{get { return health; }set{health = value;Notify();}}public void Attach(IObserver observer){observers.Add(observer);}public void Detach(IObserver observer){observers.Remove(observer);}public void Notify(){foreach (var observer in observers){observer.Update(health);}}
}// 具體觀察者類
public class HealthDisplay : IObserver
{public void Update(int value){Console.WriteLine($"生命值更新為: {value}");}
}
class Program
{static void Main(){// 創建主題對象PlayerStatus playerStatus = new PlayerStatus();// 創建觀察者對象HealthDisplay healthDisplay = new HealthDisplay();// 注冊觀察者到主題playerStatus.Attach(healthDisplay);// 改變主題狀態playerStatus.Health = 80;// 再改變一次主題狀態playerStatus.Health = 60;// 移除觀察者playerStatus.Detach(healthDisplay);// 再次改變主題狀態,此時觀察者不會收到通知playerStatus.Health = 40;}
}
- 總結:觀察者模式實現了對象間的松散耦合,主題和觀察者相互獨立,增加或刪除觀察者不會影響主題的邏輯。它使得系統的擴展性和維護性更好,適用于一個對象的狀態變化需要通知多個對象并進行相應處理的場景。
2.3.3. 迭代器模式(Iterator Pattern)
-
定義:提供一種方法順序訪問一個聚合對象中各個元素,而又不需要暴露該對象的內部表示。迭代器模式將遍歷聚合對象的責任封裝到一個迭代器對象中,使得對聚合對象的遍歷更加靈活和可復用。
-
示例場景:在游戲中,有一個包含多個游戲道具的背包系統,需要遍歷背包中的道具進行顯示、使用等操作。使用迭代器模式,可以創建一個背包迭代器,通過迭代器來遍歷背包中的道具,而不需要關心背包的具體存儲結構。
-
代碼示例(C#):
// 迭代器接口
public interface IIterator<T>
{bool MoveNext();T Current { get; }
}// 聚合接口
public interface IAggregate<T>
{IIterator<T> GetIterator();
}// 背包類(聚合實現)
public class Backpack : IAggregate<string>
{private List<string> items = new List<string>();public void AddItem(string item){items.Add(item);}public IIterator<string> GetIterator(){return new BackpackIterator(this);}
}// 背包迭代器類
public class BackpackIterator : IIterator<string>
{private Backpack backpack;private int currentIndex = 0;public BackpackIterator(Backpack backpack){this.backpack = backpack;}public bool MoveNext(){return currentIndex < backpack.items.Count;}public string Current{get{if (MoveNext()){return backpack.items[currentIndex++];}return null;}}
}
class Program
{static void Main(){// 創建背包對象Backpack backpack = new Backpack();// 向背包中添加物品backpack.AddItem("劍");backpack.AddItem("盾牌");backpack.AddItem("藥水");// 獲取背包的迭代器IIterator<string> iterator = backpack.GetIterator();// 使用迭代器遍歷背包中的物品while (iterator.MoveNext()){string item = iterator.Current;Console.WriteLine(item);}}
}
- 總結:迭代器模式簡化了聚合對象的遍歷操作,將遍歷邏輯從聚合對象中分離出來,提高了代碼的可維護性和可復用性。它適用于需要對聚合對象進行多種遍歷方式或需要隱藏聚合對象內部結構的場景。
2.3.4. 模板方法模式(Template Method Pattern)
-
定義:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。它通過抽象類定義一個模板方法,包含算法的基本步驟,部分步驟可以是抽象的,由子類實現。
-
示例場景:在游戲開發中,不同類型的游戲關卡有相似的流程,如關卡初始化、關卡更新、關卡結束處理等。使用模板方法模式,可以在抽象類中定義關卡流程的模板方法,具體的關卡類繼承抽象類,并實現其中的抽象步驟,以適應不同關卡的需求。
-
代碼示例(C#):
// 抽象關卡類
public abstract class GameLevel
{public void Play(){Initialize();Update();End();}protected abstract void Initialize();protected abstract void Update();protected abstract void End();
}// 具體關卡類
public class Level1 : GameLevel
{protected override void Initialize(){Console.WriteLine("Level1初始化");}protected override void Update(){Console.WriteLine("Level1更新");}protected override void End(){Console.WriteLine("Level1結束");}
}
class Program
{static void Main(){// 創建 Level1 關卡實例GameLevel level1 = new Level1();// 調用 Play 方法開始游戲關卡level1.Play();}
}
- 總結:模板方法模式通過定義算法骨架,將公共部分提取到抽象類中,減少了代碼重復,提高了代碼的復用性。它適用于具有相似算法結構但部分步驟需要根據具體情況定制的場景,使得代碼更加清晰和易于維護。
2.3.5. 命令模式(Command Pattern)
-
定義:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤銷的操作。命令模式將請求者和執行者解耦,通過命令對象來傳遞請求,使得請求的發送者和接收者之間的依賴關系更加松散。
-
示例場景:在游戲中,玩家的各種操作(如攻擊、移動、使用技能等)可以封裝成命令對象。這樣可以方便地實現操作的記錄、撤銷、重做等功能,也便于對操作進行集中管理和擴展。例如,實現一個游戲操作日志系統,記錄玩家的每一步操作,或者實現一個撤銷功能,讓玩家可以撤銷上一步操作。
-
代碼示例(C#):
// 命令接口
public interface ICommand
{void Execute();void Undo();
}// 攻擊命令類
public class AttackCommand : ICommand
{private Character character;public AttackCommand(Character character){this.character = character;}public void Execute(){Console.WriteLine($"{character.Name} 執行攻擊");}public void Undo(){Console.WriteLine($"{character.Name} 撤銷攻擊");}
}// 角色類
public class Character
{public string Name { get; set; }
}// 命令調用者類
public class CommandInvoker
{private Stack<ICommand> commandStack = new Stack<ICommand>();public void ExecuteCommand(ICommand command){command.Execute();commandStack.Push(command);}public void UndoLastCommand(){if (commandStack.Count > 0){ICommand command = commandStack.Pop();command.Undo();}}
}
class Program
{static void Main(){// 創建角色Character character = new Character { Name = "勇士" };// 創建命令調用者CommandInvoker invoker = new CommandInvoker();// 創建攻擊命令ICommand attackCommand = new AttackCommand(character);// 執行攻擊命令invoker.ExecuteCommand(attackCommand);// 撤銷上一個命令invoker.UndoLastCommand();}
}
- 總結:命令模式提高了系統的靈活性和可擴展性,方便實現操作的記錄、撤銷和重做等功能。它將請求封裝成對象,使得請求的處理更加靈活,適用于需要對請求進行統一管理和操作的場景,如游戲操作管理、事務處理等。
2.3.6. 狀態模式(State Pattern)
-
定義:允許一個對象在其內部狀態改變時改變它的行為。對象看起來似乎修改了它的類。狀態模式將對象的狀態封裝成獨立的狀態類,每個狀態類實現與該狀態相關的行為,當對象狀態改變時,其行為也隨之改變。
-
示例場景:在游戲中,角色有不同的狀態,如站立、行走、奔跑、攻擊、死亡等。當角色處于不同狀態時,其行為表現不同。使用狀態模式,可以將每個狀態封裝成一個狀態類,角色根據自身狀態調用相應狀態類的方法,實現不同狀態下的行為。
-
代碼示例(C#):
// 狀態接口
public interface IState
{void Handle(Character character);
}// 站立狀態類
public class StandingState : IState
{public void Handle(Character character){Console.WriteLine($"{character.Name} 處于站立狀態");}
}// 行走狀態類
public class WalkingState : IState
{public void Handle(Character character){Console.WriteLine($"{character.Name} 處于行走狀態");}
}// 角色類
public class Character
{private IState currentState;public Character(){currentState = new StandingState();}public void ChangeState(IState state){currentState = state;}public void PerformAction(){currentState.Handle(this);}
}
class Program
{static void Main(){// 創建角色Character character = new Character { Name = "玩家" };// 執行初始狀態的動作character.PerformAction();// 改變角色狀態為行走狀態character.ChangeState(new WalkingState());// 執行新狀態的動作character.PerformAction();}
}
- 總結:狀態模式使得狀態的管理和行為的實現更加清晰和易于維護,避免了大量的條件判斷語句。它適用于對象的行為隨狀態變化而變化的場景,通過將狀態和行為封裝,提高了代碼的可擴展性和可維護性。
2.3.7. 備忘錄模式(Memento Pattern)
-
定義:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可將該對象恢復到原先保存的狀態。備忘錄模式通過創建一個備忘錄對象來保存目標對象的狀態,使得對象可以在需要時恢復到之前的狀態。
-
示例場景:在游戲中,玩家在游戲過程中可能需要保存游戲進度,以便在后續繼續游戲。使用備忘錄模式,可以將玩家的游戲狀態(如角色位置、生命值、背包物品等)封裝成一個備忘錄對象,保存到文件或數據庫中。當玩家重新加載游戲時,通過讀取備忘錄對象來恢復游戲狀態。
-
代碼示例(C#):
// 備忘錄類
public class GameMemento
{public string PlayerPosition { get; set; }public int Health { get; set; }public List<string> Inventory { get; set; }public GameMemento(string playerPosition, int health, List<string> inventory){PlayerPosition = playerPosition;Health = health;Inventory = inventory;}
}// 游戲角色類
public class Player
{public string Position { get; set; }public int Health { get; set; }public List<string> Inventory { get; set; }public GameMemento SaveState(){return new GameMemento(Position, Health, new List<string>(Inventory));}public void RestoreState(GameMemento memento){Position = memento.PlayerPosition;Health = memento.Health;Inventory = memento.Inventory;}
}// 游戲存檔管理類
public class GameSaveManager
{private GameMemento memento;public void SaveGame(Player player){memento = player.SaveState();}public GameMemento LoadGame(){return memento;}
}
class Program
{static void Main(){// 創建游戲角色Player player = new Player{Position = "起點",Health = 100,Inventory = new List<string> { "劍", "盾牌" }};// 創建游戲存檔管理對象GameSaveManager saveManager = new GameSaveManager();// 保存游戲狀態saveManager.SaveGame(player);// 模擬角色狀態改變player.Position = "終點";player.Health = 50;player.Inventory.Remove("劍");// 輸出改變后的狀態Console.WriteLine($"改變后的位置: {player.Position}");Console.WriteLine($"改變后的生命值: {player.Health}");Console.WriteLine("改變后的物品欄:");foreach (var item in player.Inventory){Console.WriteLine(item);}// 恢復游戲狀態GameMemento savedState = saveManager.LoadGame();player.RestoreState(savedState);// 輸出恢復后的狀態Console.WriteLine("\n恢復后的狀態:");Console.WriteLine($"位置: {player.Position}");Console.WriteLine($"生命值: {player.Health}");Console.WriteLine("物品欄:");foreach (var item in player.Inventory){Console.WriteLine(item);}}
}
- 總結:備忘錄模式提供了一種對象狀態的備份和恢復機制,使得系統在需要時可以回到之前的狀態。它在不破壞對象封裝性的前提下實現狀態保存和恢復,適用于需要保存和恢復對象狀態的場景,如游戲存檔、事務回滾等。
2.3.8. 職責鏈模式(Chain of Responsibility Pattern)
-
定義:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。職責鏈模式通過將處理請求的對象組成一條鏈,每個對象在鏈上依次嘗試處理請求,直到有對象處理成功。
-
示例場景:在游戲中,玩家的操作可能需要經過多個模塊的處理,如權限驗證模塊、輸入合法性檢查模塊、業務邏輯處理模塊等。使用職責鏈模式,可以將這些模塊組成一條鏈,玩家的操作請求依次傳遞給鏈上的模塊進行處理,直到有模塊處理成功或請求被鏈上所有模塊拒絕。
-
代碼示例(C#):
// 抽象處理者類
public abstract class Handler
{protected Handler successor;public void SetSuccessor(Handler successor){this.successor = successor;}public abstract void HandleRequest(Request request);
}// 權限驗證處理者類
public class PermissionHandler : Handler
{public override void HandleRequest(Request request){if (request.User.HasPermission){Console.WriteLine($"用戶 {request.User.Name} 權限驗證通過");if (successor != null){successor.HandleRequest(request);}}else{Console.WriteLine($"用戶 {request.User.Name} 權限不足");}}
}// 輸入合法性檢查處理者類
public class InputValidatorHandler : Handler
{public override void HandleRequest(Request request){if (request.IsValid){Console.WriteLine("輸入合法");if (successor != null){successor.HandleRequest(request);}}else{Console.WriteLine("輸入不合法");}}
}// 請求類
public class Request
{public User User { get; set; }public bool IsValid { get; set; }
}// 用戶類
public class User
{public string Name { get; set; }public bool HasPermission { get; set; }
}
class Program
{static void Main(){// 創建處理者PermissionHandler permissionHandler = new PermissionHandler();InputValidatorHandler inputValidatorHandler = new InputValidatorHandler();// 設置責任鏈順序permissionHandler.SetSuccessor(inputValidatorHandler);// 創建用戶User user = new User{Name = "Alice",HasPermission = true};// 創建請求Request request = new Request{User = user,IsValid = true};// 從責任鏈的起始處理者開始處理請求permissionHandler.HandleRequest(request);}
}
- 總結:職責鏈模式降低了請求發送者和接收者之間的耦合度,使得系統更加靈活和可擴展。它適用于請求處理過程需要多個對象依次參與,且處理過程可以動態調整的場景,通過職責鏈的方式,提高了代碼的可維護性和擴展性。
2.3.9. 中介者模式(Mediator Pattern)
-
定義:用中介對象封裝對象間交互,降低對象耦合,使它們可獨立改變交互方式。
-
示例場景:在聊天系統中,多個用戶間聊天交互復雜。引入中介者(如聊天服務器),用戶只與中介者交互,中介者處理消息轉發等交互邏輯。
-
代碼示例(C#):
using System;
using System.Collections.Generic;// 抽象中介者
abstract class Mediator
{public abstract void Send(string message, Colleague colleague);
}// 具體中介者
class ConcreteMediator : Mediator
{private List<Colleague> colleagues = new List<Colleague>();public void Register(Colleague colleague){colleagues.Add(colleague);}public override void Send(string message, Colleague colleague){foreach (var c in colleagues){if (c != colleague){c.Receive(message);}}}
}// 抽象同事類
abstract class Colleague
{protected Mediator mediator;public Colleague(Mediator mediator){this.mediator = mediator;}public abstract void Send(string message);public abstract void Receive(string message);
}// 具體同事類
class ConcreteColleague : Colleague
{public ConcreteColleague(Mediator mediator) : base(mediator) { }public override void Send(string message){Console.WriteLine($"發送消息: {message}");mediator.Send(message, this);}public override void Receive(string message){Console.WriteLine($"接收消息: {message}");}
}class Program
{static void Main(){ConcreteMediator mediator = new ConcreteMediator();ConcreteColleague colleague1 = new ConcreteColleague(mediator);ConcreteColleague colleague2 = new ConcreteColleague(mediator);mediator.Register(colleague1);mediator.Register(colleague2);colleague1.Send("你好!");}
}
- 總結:中介者模式減少對象間直接耦合,集中管理交互邏輯,使系統更易維護和擴展。但中介者可能變得復雜,承擔過多職責。
2.3.10. 訪問者模式(Visitor Pattern)
-
定義:定義作用于對象結構中元素的操作,可在不改變元素類前提下定義新操作。
-
示例場景:在圖形編輯軟件中,有多種圖形對象(如圓形、矩形)。要實現計算圖形面積、周長等功能,用訪問者模式,為每個功能創建訪問者,不改動圖形類。
-
代碼示例(C#):
using System;// 抽象元素
abstract class Shape
{public abstract void Accept(IVisitor visitor);
}// 具體元素:圓形
class Circle : Shape
{public double Radius { get; set; }public Circle(double radius){Radius = radius;}public override void Accept(IVisitor visitor){visitor.Visit(this);}
}// 具體元素:矩形
class Rectangle : Shape
{public double Width { get; set; }public double Height { get; set; }public Rectangle(double width, double height){Width = width;Height = height;}public override void Accept(IVisitor visitor){visitor.Visit(this);}
}// 抽象訪問者
interface IVisitor
{void Visit(Circle circle);void Visit(Rectangle rectangle);
}// 具體訪問者:計算面積
class AreaVisitor : IVisitor
{public void Visit(Circle circle){Console.WriteLine($"圓形面積: {Math.PI * circle.Radius * circle.Radius}");}public void Visit(Rectangle rectangle){Console.WriteLine($"矩形面積: {rectangle.Width * rectangle.Height}");}
}class Program
{static void Main(){Shape circle = new Circle(5);Shape rectangle = new Rectangle(4, 6);IVisitor visitor = new AreaVisitor();circle.Accept(visitor);rectangle.Accept(visitor);}
}
- 總結:訪問者模式分離數據結構和操作,便于添加新操作。但增加新元素類時需修改所有訪問者類,適用于數據結構穩定、操作多變場景。
2.3.11. 解釋器模式(Interpreter Pattern)
-
定義:給定語言,定義其文法表示及解釋器,用解釋器解釋語言句子。
-
示例場景:在游戲腳本系統中,自定義腳本語言控制游戲邏輯(如角色行為)。使用解釋器模式構建語法樹并解釋執行腳本語句。
-
代碼示例(C#,簡單算術表達式):
using System;// 抽象表達式
abstract class Expression
{public abstract int Interpret();
}// 終結符表達式:數字
class NumberExpression : Expression
{private int number;public NumberExpression(int number){this.number = number;}public override int Interpret(){return number;}
}// 非終結符表達式:加法
class AddExpression : Expression
{private Expression left;private Expression right;public AddExpression(Expression left, Expression right){this.left = left;this.right = right;}public override int Interpret(){return left.Interpret() + right.Interpret();}
}class Program
{static void Main(){Expression num1 = new NumberExpression(3);Expression num2 = new NumberExpression(5);Expression addExpr = new AddExpression(num1, num2);Console.WriteLine(addExpr.Interpret());}
}
- 總結:解釋器模式分離語言文法和解釋過程,易修改擴展語言。但復雜語言會使語法樹和解釋器復雜,適用于特定領域簡單語言場景。