C#實現(xiàn)23種常見的設(shè)計模式的示例詳解
設(shè)計模式通常分為三個主要類別:
- 創(chuàng)建型模式
- 結(jié)構(gòu)型模式
- 行為型模式。
這些模式是用于解決常見的對象導(dǎo)向設(shè)計問題的最佳實踐。
以下是23種常見的設(shè)計模式并且提供c#代碼案例:
創(chuàng)建型模式
1. 單例模式(Singleton)
public sealed class Singleton { //創(chuàng)建一個只讀的靜態(tài)Singleton實例 private static readonly Singleton instance = new Singleton(); // 記錄Singleton的創(chuàng)建次數(shù) private static int instanceCounter = 0; // 單例實例的公共訪問點 public static Singleton Instance { get { return instance; } } // 私有構(gòu)造函數(shù) private Singleton() { instanceCounter++; Console.WriteLine("Instances Created " + instanceCounter); } // 在此處添加其他的Singleton類方法 public void LogMessage(string message) { Console.WriteLine("Message: " + message); } }
在這個例子中,我們有一個名為Singleton
的類,它有一個私有的構(gòu)造函數(shù)和一個靜態(tài)的只讀屬性Instance
,用于訪問Singleton
類的唯一實例。我們還有一個LogMessage
方法,用于模擬Singleton
類的某個行為。
以下是一個使用這個Singleton
類的控制臺應(yīng)用程序:
class Program { static void Main(string[] args) { Singleton fromEmployee = Singleton.Instance; fromEmployee.LogMessage("Message from Employee"); Singleton fromBoss = Singleton.Instance; fromBoss.LogMessage("Message from Boss"); Console.ReadLine(); } }
2. 工廠方法模式(Factory Method)
工廠方法模式是一種創(chuàng)建型設(shè)計模式,它提供了一種創(chuàng)建對象的接口,但允許子類決定實例化哪個類。工廠方法讓類的實例化推遲到子類中進行。
下面是一個使用C#實現(xiàn)的工廠方法模式的簡單示例:
// 抽象產(chǎn)品 public interface IProduct { string Operation(); } // 具體產(chǎn)品A public class ProductA : IProduct { public string Operation() { return "{Result of ProductA}"; } } // 具體產(chǎn)品B public class ProductB : IProduct { public string Operation() { return "{Result of ProductB}"; } } // 抽象創(chuàng)建者 public abstract class Creator { public abstract IProduct FactoryMethod(); } // 具體創(chuàng)建者A public class CreatorA : Creator { public override IProduct FactoryMethod() { return new ProductA(); } } // 具體創(chuàng)建者B public class CreatorB : Creator { public override IProduct FactoryMethod() { return new ProductB(); } }
以上代碼中定義了兩個產(chǎn)品ProductA
和ProductB
,這兩個產(chǎn)品都實現(xiàn)了IProduct
接口。接著我們有兩個Creator類,CreatorA
和CreatorB
,它們都繼承自抽象基類Creator
。CreatorA
工廠創(chuàng)建ProductA
,CreatorB
工廠創(chuàng)建ProductB
。
以下是一個使用這些工廠和產(chǎn)品的示例:
class Program { static void Main(string[] args) { // 創(chuàng)建工廠對象 Creator creatorA = new CreatorA(); Creator creatorB = new CreatorB(); // 通過工廠方法創(chuàng)建產(chǎn)品對象 IProduct productA = creatorA.FactoryMethod(); IProduct productB = creatorB.FactoryMethod(); // 打印結(jié)果 Console.WriteLine("ProductA says: " + productA.Operation()); Console.WriteLine("ProductB says: " + productB.Operation()); Console.ReadLine(); } }
當(dāng)你運行這個程序時,它會顯示出ProductA
和ProductB
的Operation
方法返回的結(jié)果。這說明我們已經(jīng)成功地使用工廠方法模式創(chuàng)建了產(chǎn)品實例。每個工廠類決定了它創(chuàng)建哪個產(chǎn)品的實例。這種方式使得客戶端代碼不需要直接實例化產(chǎn)品類,而只需要依賴工廠接口,增加了程序的靈活性。
3. 抽象工廠模式(Abstract Factory)
抽象工廠模式是一種創(chuàng)建型設(shè)計模式,它提供了一種接口,用于創(chuàng)建相關(guān)或依賴對象的系列,而不指定這些對象的具體類。在這個模式中,客戶端通過他們的抽象接口使用類,允許該模式在不影響客戶端的情況下替換實現(xiàn)類。
以下是一個簡單的抽象工廠模式的C#實現(xiàn):
// 抽象產(chǎn)品:動物 public interface IAnimal { string Speak(); } // 具體產(chǎn)品:狗 public class Dog : IAnimal { public string Speak() { return "Bark Bark"; } } // 具體產(chǎn)品:貓 public class Cat : IAnimal { public string Speak() { return "Meow Meow"; } } // 抽象工廠 public abstract class IAnimalFactory { public abstract IAnimal CreateAnimal(); } // 具體工廠:狗工廠 public class DogFactory : IAnimalFactory { public override IAnimal CreateAnimal() { return new Dog(); } } // 具體工廠:貓工廠 public class CatFactory : IAnimalFactory { public override IAnimal CreateAnimal() { return new Cat(); } }
以上代碼定義了兩種動物Dog
和Cat
,它們都實現(xiàn)了IAnimal
接口。然后我們有兩個工廠類,DogFactory
和CatFactory
,它們都繼承自IAnimalFactory
。DogFactory
生產(chǎn)Dog
,而CatFactory
生產(chǎn)Cat
。
以下是一個使用這些工廠和產(chǎn)品的示例:
class Program { static void Main(string[] args) { // 創(chuàng)建工廠 IAnimalFactory dogFactory = new DogFactory(); IAnimalFactory catFactory = new CatFactory(); // 使用工廠創(chuàng)建產(chǎn)品 IAnimal dog = dogFactory.CreateAnimal(); IAnimal cat = catFactory.CreateAnimal(); // 打印結(jié)果 Console.WriteLine("Dog says: " + dog.Speak()); Console.WriteLine("Cat says: " + cat.Speak()); Console.ReadLine(); } }
當(dāng)你運行這個程序時,會打印出Dog和Cat的Speak方法的結(jié)果,這顯示了我們已經(jīng)成功地使用了抽象工廠模式創(chuàng)建了產(chǎn)品實例。這種方式使得客戶端代碼不需要直接實例化產(chǎn)品類,而只需要依賴工廠接口,增加了程序的靈活性和擴展性。
4. 建造者模式(Builder)
建造者模式是一種創(chuàng)建型設(shè)計模式,它提供了一種創(chuàng)建對象的接口,但是允許使用相同的構(gòu)建過程來創(chuàng)建不同的產(chǎn)品。
以下是在C#中實現(xiàn)建造者模式的一個簡單示例:
// 產(chǎn)品 public class Car { public string Engine { get; set; } public string Wheels { get; set; } public string Doors { get; set; } } // 建造者抽象類 public abstract class CarBuilder { protected Car car; public void CreateNewCar() { car = new Car(); } public Car GetCar() { return car; } public abstract void SetEngine(); public abstract void SetWheels(); public abstract void SetDoors(); } // 具體建造者 public class FerrariBuilder : CarBuilder { public override void SetEngine() { car.Engine = "V8"; } public override void SetWheels() { car.Wheels = "18 inch"; } public override void SetDoors() { car.Doors = "2"; } } // 指揮者 public class Director { public Car Construct(CarBuilder carBuilder) { carBuilder.CreateNewCar(); carBuilder.SetEngine(); carBuilder.SetWheels(); carBuilder.SetDoors(); return carBuilder.GetCar(); } }
以上代碼中,Car
是我們要創(chuàng)建的產(chǎn)品,CarBuilder
是抽象的建造者,定義了制造一個產(chǎn)品所需要的各個步驟,FerrariBuilder
是具體的建造者,實現(xiàn)了CarBuilder
定義的所有步驟,Director
是指揮者,它告訴建造者應(yīng)該按照什么順序去執(zhí)行哪些步驟。
以下是一個使用這個建造者模式的示例:
class Program { static void Main(string[] args) { Director director = new Director(); CarBuilder builder = new FerrariBuilder(); Car ferrari = director.Construct(builder); Console.WriteLine($"Engine: {ferrari.Engine}, Wheels: {ferrari.Wheels}, Doors: {ferrari.Doors}"); Console.ReadLine(); } }
當(dāng)你運行這個程序時,會看到我們已經(jīng)成功地創(chuàng)建了一個Car
實例,它的各個部分是按照FerrariBuilder
所定義的方式創(chuàng)建的。這說明我們使用建造者模式成功地將一個復(fù)雜對象的構(gòu)造過程解耦,使得同樣的構(gòu)造過程可以創(chuàng)建不同的表示。
5. 原型模式(Prototype)
原型模式是一種創(chuàng)建型設(shè)計模式,它實現(xiàn)了一個原型接口,該接口用于創(chuàng)建當(dāng)前對象的克隆。當(dāng)直接創(chuàng)建對象的代價比較大時,則采用這種模式。例如,一個對象需要在一個高代價的數(shù)據(jù)庫操作后被創(chuàng)建。
以下是在C#中實現(xiàn)原型模式的一個簡單示例:
// 抽象原型 public interface IPrototype { IPrototype Clone(); } // 具體原型 public class ConcretePrototype : IPrototype { public string Name { get; set; } public int Value { get; set; } public IPrototype Clone() { // 實現(xiàn)深拷貝 return (ConcretePrototype)this.MemberwiseClone(); // Clones the concrete object. } }
以上代碼定義了一個ConcretePrototype
類,它實現(xiàn)了IPrototype
接口。接口定義了一個Clone
方法,用于復(fù)制對象。在ConcretePrototype
類中,我們使用了MemberwiseClone
方法來創(chuàng)建一個新的克隆對象。
以下是一個使用原型模式的示例:
class Program { static void Main(string[] args) { ConcretePrototype prototype = new ConcretePrototype(); prototype.Name = "Original"; prototype.Value = 10; Console.WriteLine("Original instance: " + prototype.Name + ", " + prototype.Value); ConcretePrototype clone = (ConcretePrototype)prototype.Clone(); Console.WriteLine("Cloned instance: " + clone.Name + ", " + clone.Value); Console.ReadLine(); } }
在這個例子中,我們創(chuàng)建了一個ConcretePrototype
對象,并為其屬性賦值,然后我們調(diào)用Clone
方法創(chuàng)建了一個新的ConcretePrototype
對象。當(dāng)我們運行這個程序時,會看到原始對象和克隆對象的屬性是相同的,這表明我們已經(jīng)成功地克隆了一個對象。
執(zhí)行流程如下:
- 創(chuàng)建一個具體的原型對象,為其屬性賦值。
- 調(diào)用原型對象的
Clone
方法,創(chuàng)建一個新的對象,該對象的屬性與原型對象的屬性相同。 - 打印原型對象和克隆對象的屬性,驗證它們是否相同。
結(jié)構(gòu)型模式
1. 橋接模式(Bridge)
橋接模式是一種結(jié)構(gòu)型設(shè)計模式,用于將抽象部分與其實現(xiàn)部分分離,使它們都可以獨立地變化。
以下是在C#中實現(xiàn)橋接模式的一個簡單示例:
// 實現(xiàn)類接口 public interface IImplementor { void OperationImp(); } // 具體實現(xiàn)類A public class ConcreteImplementorA : IImplementor { public void OperationImp() { Console.WriteLine("Concrete Implementor A"); } } // 具體實現(xiàn)類B public class ConcreteImplementorB : IImplementor { public void OperationImp() { Console.WriteLine("Concrete Implementor B"); } } // 抽象類 public abstract class Abstraction { protected IImplementor implementor; public Abstraction(IImplementor implementor) { this.implementor = implementor; } public virtual void Operation() { implementor.OperationImp(); } } // 擴充的抽象類 public class RefinedAbstraction : Abstraction { public RefinedAbstraction(IImplementor implementor) : base(implementor) { } public override void Operation() { Console.WriteLine("Refined Abstraction is calling implementor's method:"); base.Operation(); } }
在這個代碼中,Abstraction
是抽象類,它有一個IImplementor
接口的實例,通過這個實例調(diào)用實現(xiàn)類的方法。RefinedAbstraction
是擴充的抽象類,它繼承自Abstraction
。ConcreteImplementorA
和ConcreteImplementorB
是實現(xiàn)類,它們實現(xiàn)了IImplementor
接口。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { IImplementor implementorA = new ConcreteImplementorA(); Abstraction abstractionA = new RefinedAbstraction(implementorA); abstractionA.Operation(); IImplementor implementorB = new ConcreteImplementorB(); Abstraction abstractionB = new RefinedAbstraction(implementorB); abstractionB.Operation(); Console.ReadLine(); } }
在這個例子中,我們創(chuàng)建了兩個實現(xiàn)類的實例,然后創(chuàng)建了兩個抽象類的實例,每個抽象類的實例都有一個實現(xiàn)類的實例。當(dāng)我們調(diào)用抽象類的Operation
方法時,它會調(diào)用實現(xiàn)類的OperationImp
方法。
執(zhí)行流程如下:
- 創(chuàng)建實現(xiàn)類的實例。
- 創(chuàng)建抽象類的實例,抽象類的實例有一個實現(xiàn)類的實例。
- 調(diào)用抽象類的
Operation
方法,該方法會調(diào)用實現(xiàn)類的OperationImp
方法。
2. 組合模式(Composite)
組合模式(Composite pattern)是一種結(jié)構(gòu)型設(shè)計模式,它可以使你將對象組合成樹形結(jié)構(gòu),并且能像使用獨立對象一樣使用它們。這種模式的主要目的是使單個對象和組合對象具有一致性。
以下是在C#中實現(xiàn)組合模式的一個簡單示例:
// 抽象組件類 public abstract class Component { protected string name; public Component(string name) { this.name = name; } public abstract void Add(Component c); public abstract void Remove(Component c); public abstract void Display(int depth); } // 葉節(jié)點類 public class Leaf : Component { public Leaf(string name) : base(name) { } public override void Add(Component c) { Console.WriteLine("Cannot add to a leaf"); } public override void Remove(Component c) { Console.WriteLine("Cannot remove from a leaf"); } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); } } // 構(gòu)件容器類 public class Composite : Component { private List<Component> _children = new List<Component>(); public Composite(string name) : base(name) { } public override void Add(Component component) { _children.Add(component); } public override void Remove(Component component) { _children.Remove(component); } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); // 顯示每個節(jié)點的子節(jié)點 foreach (Component component in _children) { component.Display(depth + 2); } } }
在這個代碼中,Component
是組件抽象類,它有一個名字,并定義了添加、刪除和顯示操作。Leaf
是葉子節(jié)點,它實現(xiàn)了Component
的操作。Composite
是組件容器,它可以添加、刪除和顯示其子節(jié)點。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { Composite root = new Composite("root"); root.Add(new Leaf("Leaf A")); root.Add(new Leaf("Leaf B")); Composite comp = new Composite("Composite X"); comp.Add(new Leaf("Leaf XA")); comp.Add(new Leaf("Leaf XB")); root.Add(comp); Composite comp2 = new Composite("Composite XY"); comp2.Add(new Leaf("Leaf XYA")); comp2.Add(new Leaf("Leaf XYB")); comp.Add(comp2); root.Add(new Leaf("Leaf C")); // 在組合中添加和刪除 Leaf leaf = new Leaf("Leaf D"); root.Add(leaf); root.Remove(leaf); // 顯示樹形結(jié)構(gòu) root.Display(1); Console.ReadLine(); } }
在這個例子中,我們創(chuàng)建了一個根節(jié)點,并在其中添加了兩個葉子節(jié)點。然后我們創(chuàng)建了一個復(fù)合節(jié)點,并在其中添加了兩個葉子節(jié)點,然后我們把復(fù)合節(jié)點添加到根節(jié)點中。我們還在復(fù)合節(jié)點中添加了另一個復(fù)合節(jié)點。最后,我們又在根節(jié)點中添加和刪除了一個葉子節(jié)點,然后顯示了樹的結(jié)構(gòu)。
執(zhí)行流程如下:
- 創(chuàng)建組合和葉子對象。
- 通過調(diào)用組合對象的
Add
方法將葉子對象和其他組合對象添加到組合對象中。 - 通過調(diào)用組合對象的
Remove
方法將葉子對象從組合對象中移除。 - 調(diào)用組合對象的
Display
方法顯示組合對象的結(jié)構(gòu)。
3. 裝飾模式(Decorator)
裝飾模式是一種結(jié)構(gòu)型設(shè)計模式,它允許在運行時動態(tài)地將功能添加到對象中,這種模式提供了比繼承更有彈性的解決方案。
以下是在C#中實現(xiàn)裝飾模式的一個簡單示例:
// 抽象組件 public abstract class Component { public abstract string Operation(); } // 具體組件 public class ConcreteComponent : Component { public override string Operation() { return "ConcreteComponent"; } } // 抽象裝飾器 public abstract class Decorator : Component { protected Component component; public Decorator(Component component) { this.component = component; } public override string Operation() { if (component != null) { return component.Operation(); } else { return string.Empty; } } } // 具體裝飾器A public class ConcreteDecoratorA : Decorator { public ConcreteDecoratorA(Component comp) : base(comp) { } public override string Operation() { return $"ConcreteDecoratorA({base.Operation()})"; } } // 具體裝飾器B public class ConcreteDecoratorB : Decorator { public ConcreteDecoratorB(Component comp) : base(comp) { } public override string Operation() { return $"ConcreteDecoratorB({base.Operation()})"; } }
在這個代碼中,Component
是一個抽象組件,它定義了一個Operation
方法。ConcreteComponent
是具體組件,它實現(xiàn)了Component
的Operation
方法。Decorator
是一個抽象裝飾器,它包含一個Component
對象,并重寫了Operation
方法。ConcreteDecoratorA
和ConcreteDecoratorB
是具體的裝飾器,它們繼承了Decorator
并重寫了Operation
方法,以添加新的功能。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { // 基本組件 Component component = new ConcreteComponent(); Console.WriteLine("Basic Component: " + component.Operation()); // 裝飾后的組件 Component decoratorA = new ConcreteDecoratorA(component); Console.WriteLine("A Decorated: " + decoratorA.Operation()); Component decoratorB = new ConcreteDecoratorB(decoratorA); Console.WriteLine("B Decorated: " + decoratorB.Operation()); Console.ReadLine(); } }
在這個例子中,我們首先創(chuàng)建了一個ConcreteComponent
對象,并調(diào)用它的Operation
方法。然后我們創(chuàng)建了一個ConcreteDecoratorA
對象,它裝飾了ConcreteComponent
,并調(diào)用它的Operation
方法。最后,我們創(chuàng)建了一個ConcreteDecoratorB
對象,它裝飾了ConcreteDecoratorA
,并調(diào)用它的Operation
方法。這樣,我們就可以在運行時動態(tài)地添加功能。
執(zhí)行流程如下:
- 創(chuàng)建一個具體組件對象并調(diào)用其操作。
- 創(chuàng)建一個裝飾器對象,該對象裝飾了具體組件,并調(diào)用其操作。在操作中,裝飾器首先調(diào)用具體組件的操作,然后執(zhí)行額外的操作。
- 創(chuàng)建另一個裝飾器對象,裝飾前一個裝飾器,并調(diào)用其操作。在操作中,這個裝飾器首先調(diào)用前一個裝飾器的操作,然后執(zhí)行額外的操作。
4. 外觀模式(Facade)
外觀模式是一種結(jié)構(gòu)型設(shè)計模式,提供了一個統(tǒng)一的接口,用來訪問子系統(tǒng)中的一群接口。外觀模式定義了一個高層接口,讓子系統(tǒng)更容易使用。
以下是在C#中實現(xiàn)外觀模式的一個簡單示例:
// 子系統(tǒng)A public class SubSystemA { public string OperationA() { return "SubSystemA, OperationA\n"; } } // 子系統(tǒng)B public class SubSystemB { public string OperationB() { return "SubSystemB, OperationB\n"; } } // 子系統(tǒng)C public class SubSystemC { public string OperationC() { return "SubSystemC, OperationC\n"; } } // 外觀類 public class Facade { private SubSystemA a = new SubSystemA(); private SubSystemB b = new SubSystemB(); private SubSystemC c = new SubSystemC(); public string OperationWrapper() { string result = "Facade initializes subsystems:\n"; result += a.OperationA(); result += b.OperationB(); result += c.OperationC(); return result; } }
在這個代碼中,SubSystemA
,SubSystemB
和SubSystemC
都是子系統(tǒng),每個子系統(tǒng)都有一個操作。Facade
是一個外觀類,它封裝了對子系統(tǒng)的操作,提供了一個統(tǒng)一的接口。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { Facade facade = new Facade(); Console.WriteLine(facade.OperationWrapper()); Console.ReadLine(); } }
在這個例子中,我們創(chuàng)建了一個Facade
對象,并調(diào)用了它的OperationWrapper
方法。這個方法封裝了對子系統(tǒng)的操作,使得客戶端可以不直接操作子系統(tǒng),而是通過外觀類操作子系統(tǒng)。
執(zhí)行流程如下:
- 創(chuàng)建一個外觀對象。
- 通過調(diào)用外觀對象的方法,間接地操作子系統(tǒng)。
- 子系統(tǒng)的操作被封裝在外觀對象的方法中,客戶端不需要直接操作子系統(tǒng)。
5. 享元模式(Flyweight)
享元模式(Flyweight Pattern)是一種結(jié)構(gòu)型設(shè)計模式,該模式主要用于減少創(chuàng)建對象的數(shù)量,以減少內(nèi)存占用和提高性能。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式,它提供了一種減少對象數(shù)量從而改善應(yīng)用所需的對象結(jié)構(gòu)的方式。
以下是在C#中實現(xiàn)享元模式的一個簡單示例:
// 享元類 public class Flyweight { private string intrinsicState; // 構(gòu)造函數(shù) public Flyweight(string intrinsicState) { this.intrinsicState = intrinsicState; } // 業(yè)務(wù)方法 public void Operation(string extrinsicState) { Console.WriteLine($"Intrinsic State = {intrinsicState}, Extrinsic State = {extrinsicState}"); } } // 享元工廠類 public class FlyweightFactory { private Dictionary<string, Flyweight> flyweights = new Dictionary<string, Flyweight>(); public Flyweight GetFlyweight(string key) { if (!flyweights.ContainsKey(key)) { flyweights[key] = new Flyweight(key); } return flyweights[key]; } public int GetFlyweightCount() { return flyweights.Count; } }
在這個代碼中,Flyweight
是享元類,它有一個內(nèi)在狀態(tài)intrinsicState
,這個狀態(tài)是不變的。FlyweightFactory
是享元工廠類,它維護了一個享元對象的集合。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { FlyweightFactory factory = new FlyweightFactory(); Flyweight flyweightA = factory.GetFlyweight("A"); flyweightA.Operation("A operation"); Flyweight flyweightB = factory.GetFlyweight("B"); flyweightB.Operation("B operation"); Flyweight flyweightC = factory.GetFlyweight("A"); flyweightC.Operation("C operation"); Console.WriteLine($"Total Flyweights: {factory.GetFlyweightCount()}"); Console.ReadLine(); } }
在這個例子中,我們創(chuàng)建了一個FlyweightFactory
對象,并通過它創(chuàng)建了兩個享元對象。注意,當(dāng)我們試圖創(chuàng)建第三個享元對象時,工廠實際上返回了第一個享元對象的引用,因為這兩個對象的內(nèi)在狀態(tài)是相同的。
執(zhí)行流程如下:
- 創(chuàng)建一個享元工廠對象。
- 通過享元工廠獲取享元對象。如果對象已經(jīng)存在,則返回現(xiàn)有對象;否則,創(chuàng)建新對象。
- 執(zhí)行享元對象的操作。
- 顯示當(dāng)前享元對象的數(shù)量。
6. 代理模式(Proxy)
代理模式是一種結(jié)構(gòu)型設(shè)計模式,它提供了一個對象代替另一個對象來控制對它的訪問。代理對象可以在客戶端和目標(biāo)對象之間起到中介的作用,并添加其他的功能。
以下是在C#中實現(xiàn)代理模式的一個簡單示例:
// 抽象主題接口 public interface ISubject { void Request(); } // 真實主題 public class RealSubject : ISubject { public void Request() { Console.WriteLine("RealSubject: Handling Request."); } } // 代理 public class Proxy : ISubject { private RealSubject _realSubject; public Proxy(RealSubject realSubject) { this._realSubject = realSubject; } public void Request() { if (this.CheckAccess()) { this._realSubject.Request(); this.LogAccess(); } } public bool CheckAccess() { // 檢查是否有權(quán)限訪問 Console.WriteLine("Proxy: Checking access prior to firing a real request."); return true; } public void LogAccess() { // 記錄請求 Console.WriteLine("Proxy: Logging the time of request."); } }
在這個代碼中,ISubject
是一個接口,定義了Request
方法。RealSubject
是實現(xiàn)了ISubject
接口的類,Proxy
是代理類,它也實現(xiàn)了ISubject
接口,并持有一個RealSubject
對象的引用。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { Console.WriteLine("Client: Executing the client code with a real subject:"); RealSubject realSubject = new RealSubject(); realSubject.Request(); Console.WriteLine(); Console.WriteLine("Client: Executing the same client code with a proxy:"); Proxy proxy = new Proxy(realSubject); proxy.Request(); Console.ReadLine(); } }
在這個例子中,我們首先直接調(diào)用了RealSubject
的Request
方法,然后我們通過代理調(diào)用了相同的方法。注意,在通過代理調(diào)用Request
方法時,代理還執(zhí)行了其他的操作,如檢查訪問權(quán)限和記錄日志。
執(zhí)行流程如下:
- 創(chuàng)建一個真實主題對象,并直接調(diào)用其
Request
方法。 - 創(chuàng)建一個代理對象,代理對象包含一個真實主題的引用。
- 通過代理對象調(diào)用
Request
方法。在這個方法中,代理首先檢查訪問權(quán)限,然后調(diào)用真實主題的Request
方法,最后記錄日志。
行為型模式
1. 命令模式(Command)
命令模式(Command Pattern)是一種數(shù)據(jù)驅(qū)動的設(shè)計模式,它屬于行為型模式。在命令模式中,請求在對象中封裝成為一個操作或行為,這些請求被送到調(diào)用對象,調(diào)用對象尋找可以處理該命令的合適的對象,并把命令直接送達到對應(yīng)的對象,該對象會執(zhí)行這些命令。
以下是在C#中實現(xiàn)命令模式的一個簡單示例:
// 命令接口 public interface ICommand { void Execute(); } // 具體命令類 public class ConcreteCommand : ICommand { private Receiver receiver; public ConcreteCommand(Receiver receiver) { this.receiver = receiver; } public void Execute() { receiver.Action(); } } // 接收者類 public class Receiver { public void Action() { Console.WriteLine("Receiver performs an action"); } } // 調(diào)用者或發(fā)送者類 public class Invoker { private ICommand command; public void SetCommand(ICommand command) { this.command = command; } public void ExecuteCommand() { command.Execute(); } }
在這個代碼中,ICommand
是命令接口,定義了Execute
方法。ConcreteCommand
是具體的命令類,它實現(xiàn)了ICommand
接口,并持有一個Receiver
對象的引用。Invoker
是調(diào)用者或發(fā)送者類,它持有一個ICommand
對象的引用,并可以通過SetCommand
方法設(shè)置命令,通過ExecuteCommand
方法執(zhí)行命令。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { Receiver receiver = new Receiver(); ICommand command = new ConcreteCommand(receiver); Invoker invoker = new Invoker(); invoker.SetCommand(command); invoker.ExecuteCommand(); Console.ReadLine(); } }
在這個例子中,我們創(chuàng)建了一個Receiver
對象、一個ConcreteCommand
對象和一個Invoker
對象。然后我們通過Invoker
的SetCommand
方法設(shè)置了命令,并通過ExecuteCommand
方法執(zhí)行了命令。
執(zhí)行流程如下:
- 創(chuàng)建一個接收者對象。
- 創(chuàng)建一個具體命令對象,并將接收者對象傳遞給它。
- 創(chuàng)建一個調(diào)用者或發(fā)送者對象。
- 通過調(diào)用者對象的
SetCommand
方法設(shè)置命令。 - 通過調(diào)用者對象的
ExecuteCommand
方法執(zhí)行命令。
2. 解釋器模式(Interpreter)
解釋器模式(Interpreter Pattern)是一種行為型設(shè)計模式,用于解決一些固定語法格式的需求。它定義了如何在語言中表示和解析語法。
以下是在C#中實現(xiàn)解釋器模式的一個簡單示例:
// 抽象表達式 public interface IExpression { bool Interpret(string context); } // 終結(jié)符表達式 public class TerminalExpression : IExpression { private string data; public TerminalExpression(string data) { this.data = data; } public bool Interpret(string context) { if (context.Contains(data)) { return true; } return false; } } // 非終結(jié)符表達式 public class OrExpression : IExpression { private IExpression expr1 = null; private IExpression expr2 = null; public OrExpression(IExpression expr1, IExpression expr2) { this.expr1 = expr1; this.expr2 = expr2; } public bool Interpret(string context) { return expr1.Interpret(context) || expr2.Interpret(context); } }
在這個代碼中,IExpression
是抽象表達式,定義了Interpret
方法。TerminalExpression
是終結(jié)符表達式,它實現(xiàn)了IExpression
接口。OrExpression
是非終結(jié)符表達式,它也實現(xiàn)了IExpression
接口。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { IExpression isMale = GetMaleExpression(); IExpression isMarriedWoman = GetMarriedWomanExpression(); Console.WriteLine($"John is male? {isMale.Interpret("John")}"); Console.WriteLine($"Julie is a married women? {isMarriedWoman.Interpret("Married Julie")}"); Console.ReadLine(); } // 規(guī)則:Robert 和 John 是男性 public static IExpression GetMaleExpression() { IExpression robert = new TerminalExpression("Robert"); IExpression john = new TerminalExpression("John"); return new OrExpression(robert, john); } // 規(guī)則:Julie 是一個已婚的女性 public static IExpression GetMarriedWomanExpression() { IExpression julie = new TerminalExpression("Julie"); IExpression married = new TerminalExpression("Married"); return new OrExpression(julie, married); } }
在這個例子中,我們定義了兩個規(guī)則,"Robert和John是男性"和"Julie是一個已婚的女性"。我們?nèi)缓髣?chuàng)建了兩個表達式對象,分別表示這兩個規(guī)則,并使用這兩個對象來解析輸入。
執(zhí)行流程如下:
- 創(chuàng)建終結(jié)符表達式對象和非終結(jié)符表達式對象,用于表示規(guī)則。
- 調(diào)用表達式對象的
Interpret
方法,解析輸入的字符串。 - 輸出解析結(jié)果。
3. 迭代器模式(Iterator)
迭代器模式(Iterator Pattern)是一種行為型設(shè)計模式,它提供了一種方法來訪問一個對象的元素,而不需要暴露該對象的內(nèi)部表示。以下是在C#中實現(xiàn)迭代器模式的一個簡單示例:
// 抽象聚合類 public interface IAggregate { IIterator CreateIterator(); void Add(string item); int Count { get; } string this[int index] { get; set; } } // 具體聚合類 public class ConcreteAggregate : IAggregate { private List<string> items = new List<string>(); public IIterator CreateIterator() { return new ConcreteIterator(this); } public int Count { get { return items.Count; } } public string this[int index] { get { return items[index]; } set { items.Insert(index, value); } } public void Add(string item) { items.Add(item); } } // 抽象迭代器 public interface IIterator { string First(); string Next(); bool IsDone { get; } string CurrentItem { get; } } // 具體迭代器 public class ConcreteIterator : IIterator { private ConcreteAggregate aggregate; private int current = 0; public ConcreteIterator(ConcreteAggregate aggregate) { this.aggregate = aggregate; } public string First() { return aggregate[0]; } public string Next() { string ret = null; if (current < aggregate.Count - 1) { ret = aggregate[++current]; } return ret; } public string CurrentItem { get { return aggregate[current]; } } public bool IsDone { get { return current >= aggregate.Count; } } }
在這個代碼中,IAggregate
是抽象聚合類,定義了CreateIterator
等方法,ConcreteAggregate
是具體聚合類,實現(xiàn)了IAggregate
接口。IIterator
是抽象迭代器,定義了First
、Next
等方法,ConcreteIterator
是具體迭代器,實現(xiàn)了IIterator
接口。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { IAggregate aggregate = new ConcreteAggregate(); aggregate.Add("Item A"); aggregate.Add("Item B"); aggregate.Add("Item C"); aggregate.Add("Item D"); IIterator iterator = aggregate.CreateIterator(); Console.WriteLine("Iterating over collection:"); string item = iterator.First(); while (item != null) { Console.WriteLine(item); item = iterator.Next(); } Console.ReadLine(); } }
在這個例子中,我們創(chuàng)建了一個ConcreteAggregate
對象,并添加了幾個元素。然后我們通過CreateIterator
方法創(chuàng)建了一個迭代器,并使用這個迭代器遍歷了集合中的所有元素。
執(zhí)行流程如下:
- 創(chuàng)建一個聚合對象,并添加一些元素。
- 通過聚合對象的
CreateIterator
方法創(chuàng)建一個迭代器。 - 通過迭代器的
First
方法獲取第一個元素,然后通過Next
方法獲取后續(xù)的元素,直到獲取不到元素為止。
4. 中介者模式(Mediator)
中介者模式是一種行為設(shè)計模式,它讓你能減少一組對象之間復(fù)雜的通信。它提供了一個中介者對象,此對象負責(zé)在組中的對象之間進行通信,而不是這些對象直接進行通信。
首先,讓我們定義一個中介者接口和一個具體的中介者:
// Mediator 接口聲明了與組件交互的方法。 public interface IMediator { void Notify(object sender, string ev); } // 具體 Mediators 實現(xiàn)協(xié)作行為,它負責(zé)協(xié)調(diào)多個組件。 public class ConcreteMediator : IMediator { private Component1 _component1; private Component2 _component2; public ConcreteMediator(Component1 component1, Component2 component2) { _component1 = component1; _component1.SetMediator(this); _component2 = component2; _component2.SetMediator(this); } public void Notify(object sender, string ev) { if (ev == "A") { Console.WriteLine("Mediator reacts on A and triggers following operations:"); this._component2.DoC(); } if (ev == "D") { Console.WriteLine("Mediator reacts on D and triggers following operations:"); this._component1.DoB(); this._component2.DoC(); } } }
接著,我們定義一個基礎(chǔ)組件類和兩個具體組件:
public abstract class BaseComponent { protected IMediator _mediator; public BaseComponent(IMediator mediator = null) { _mediator = mediator; } public void SetMediator(IMediator mediator) { this._mediator = mediator; } } // 具體 Components 實現(xiàn)各種功能。它們不依賴于其他組件。 // 它們也不依賴于任何具體 Mediator 類。 public class Component1 : BaseComponent { public void DoA() { Console.WriteLine("Component 1 does A."); this._mediator.Notify(this, "A"); } public void DoB() { Console.WriteLine("Component 1 does B."); this._mediator.Notify(this, "B"); } } public class Component2 : BaseComponent { public void DoC() { Console.WriteLine("Component 2 does C."); this._mediator.Notify(this, "C"); } public void DoD() { Console.WriteLine("Component 2 does D."); this._mediator.Notify(this, "D"); } }
最后,我們來創(chuàng)建一個客戶端代碼:
class Program { static void Main(string[] args) { // The client code. Component1 component1 = new Component1(); Component2 component2 = new Component2(); new ConcreteMediator(component1, component2); Console.WriteLine("Client triggers operation A."); component1.DoA(); Console.WriteLine(); Console.WriteLine("Client triggers operation D."); component2.DoD(); } }
這個示例中的各個組件通過中介者來進行通信,而不是直接通信,這樣就可以減少組件之間的依賴性,使得它們可以更容易地被獨立修改。當(dāng)一個組件發(fā)生某個事件(例如"Component 1 does A")時,它會通過中介者來通知其他組件,這樣其他組件就可以根據(jù)這個事件來做出響應(yīng)(例如"Component 2 does C")。
5. 備忘錄模式(Memento)
備忘錄模式是一種行為設(shè)計模式,它能保存對象的狀態(tài),以便在后面可以恢復(fù)它。在大多數(shù)情況下,這種模式可以讓你在不破壞對象封裝的前提下,保存和恢復(fù)對象的歷史狀態(tài)。
以下是一個簡單的備忘錄模式的實現(xiàn),其中有三個主要的類:Originator
(保存了一個重要的狀態(tài),這個狀態(tài)可能會隨著時間改變),Memento
(保存了Originator
的一個快照,這個快照包含了Originator
的狀態(tài)),以及Caretaker
(負責(zé)保存Memento
)。
// Originator 類可以生成一個備忘錄,并且可以通過備忘錄恢復(fù)其狀態(tài)。 public class Originator { private string _state; public Originator(string state) { this._state = state; Console.WriteLine($"Originator: My initial state is: {_state}"); } public void DoSomething() { Console.WriteLine("Originator: I'm doing something important."); _state = GenerateRandomString(30); Console.WriteLine($"Originator: and my state has changed to: {_state}"); } private string GenerateRandomString(int length = 10) { string allowedSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; string result = string.Empty; while (length > 0) { result += allowedSymbols[new Random().Next(0, allowedSymbols.Length)]; length--; } return result; } public IMemento Save() { return new ConcreteMemento(_state); } public void Restore(IMemento memento) { _state = memento.GetState(); Console.WriteLine($"Originator: My state has changed to: {_state}"); } } // 備忘錄接口提供了獲取備忘錄和原發(fā)器狀態(tài)的方法。但在該接口中并未聲明所有的方法,一些方法只在原發(fā)器中聲明。 public interface IMemento { string GetName(); string GetState(); DateTime GetDate(); } // Concrete Memento 存儲原發(fā)器狀態(tài),并通過原發(fā)器實現(xiàn)備份。備忘錄是不可變的,因此,沒有 set 方法。 public class ConcreteMemento : IMemento { private string _state; private DateTime _date; public ConcreteMemento(string state) { _state = state; _date = DateTime.Now; } public string GetState() { return _state; } public string GetName() { return $"{_date} / ({_state.Substring(0, 9)})..."; } public DateTime GetDate() { return _date; } } // Caretaker 不依賴于具體備忘錄類。結(jié)果,它不會有任何訪問原發(fā)器狀態(tài)的權(quán)利,它只能獲取備忘錄的元數(shù)據(jù)。 public class Caretaker { private List<IMemento> _mementos = new List<IMemento>(); private Originator _originator = null; public Caretaker(Originator originator) { this._originator = originator; } public void Backup() { Console.WriteLine("\nCaretaker: Saving Originator's state..."); _mementos.Add(_originator.Save()); } public void Undo() { if (_mementos.Count == 0) { return; } var memento = _mementos.Last(); _mementos.Remove(memento); Console.WriteLine("Caretaker: Restoring state to: " + memento.GetName()); try { _originator.Restore(memento); } catch (Exception) { Undo(); } } public void ShowHistory() { Console.WriteLine("Caretaker: Here's the list of mementos:"); foreach (var memento in _mementos) { Console.WriteLine(memento.GetName()); } } } // 客戶端代碼 class Program { static void Main(string[] args) { Originator originator = new Originator("Super-duper-super-puper-super."); Caretaker caretaker = new Caretaker(originator); caretaker.Backup(); originator.DoSomething(); caretaker.Backup(); originator.DoSomething(); caretaker.Backup(); originator.DoSomething(); Console.WriteLine(); caretaker.ShowHistory(); Console.WriteLine("\nClient: Now, let's rollback!\n"); caretaker.Undo(); Console.WriteLine("\nClient: Once more!\n"); caretaker.Undo(); } }
以上的代碼中,Originator 持有一些重要的狀態(tài),并且提供了方法去保存它的狀態(tài)到一個備忘錄對象以及從備忘錄對象中恢復(fù)它的狀態(tài)。Caretaker 負責(zé)保存?zhèn)渫洠撬荒懿僮鱾渫泴ο笾械臓顟B(tài)。當(dāng)用戶執(zhí)行操作時,我們先保存當(dāng)前的狀態(tài),然后執(zhí)行操作。如果用戶后來不滿意新的狀態(tài),他們可以方便地從舊的備忘錄中恢復(fù)狀態(tài)。
6. 觀察者模式(Observer)
觀察者模式(Observer Pattern)是一種行為型設(shè)計模式,當(dāng)一個對象的狀態(tài)發(fā)生變化時,依賴它的所有對象都會得到通知并被自動更新。以下是在C#中實現(xiàn)觀察者模式的一個簡單示例:
// 抽象觀察者 public interface IObserver { void Update(); } // 具體觀察者 public class ConcreteObserver : IObserver { private string name; public ConcreteObserver(string name) { this.name = name; } public void Update() { Console.WriteLine($"{name} received an update!"); } } // 抽象主題 public interface ISubject { void RegisterObserver(IObserver observer); void RemoveObserver(IObserver observer); void NotifyObservers(); } // 具體主題 public class ConcreteSubject : ISubject { private List<IObserver> observers = new List<IObserver>(); public void RegisterObserver(IObserver observer) { observers.Add(observer); } public void RemoveObserver(IObserver observer) { if (observers.Contains(observer)) { observers.Remove(observer); } } public void NotifyObservers() { foreach (var observer in observers) { observer.Update(); } } public void ChangeState() { // 觸發(fā)狀態(tài)變化,通知所有觀察者 NotifyObservers(); } }
在這個代碼中,IObserver
是抽象觀察者,定義了Update
方法,ConcreteObserver
是具體觀察者,實現(xiàn)了IObserver
接口。ISubject
是抽象主題,定義了RegisterObserver
、RemoveObserver
和NotifyObservers
方法,ConcreteSubject
是具體主題,實現(xiàn)了ISubject
接口。
以下是一個使用這個模式的示例:
class Program { static void Main(string[] args) { ConcreteSubject subject = new ConcreteSubject(); subject.RegisterObserver(new ConcreteObserver("Observer 1")); subject.RegisterObserver(new ConcreteObserver("Observer 2")); subject.RegisterObserver(new ConcreteObserver("Observer 3")); subject.ChangeState(); Console.ReadLine(); } }
在這個例子中,我們創(chuàng)建了一個ConcreteSubject
對象,并注冊了三個觀察者。然后我們通過ChangeState
方法改變了主題的狀態(tài),這會觸發(fā)主題通知所有觀察者。
執(zhí)行流程如下:
- 創(chuàng)建一個具體主題對象。
- 創(chuàng)建幾個具體觀察者對象,并通過主題的
RegisterObserver
方法將這些觀察者注冊到主題中。 - 通過主題的
ChangeState
方法改變主題的狀態(tài),這會觸發(fā)主題通知所有觀察者。
7. 狀態(tài)模式(State)
狀態(tài)模式在面向?qū)ο缶幊讨校且环N允許對象在其內(nèi)部狀態(tài)改變時改變其行為的設(shè)計模式。這種類型的設(shè)計模式屬于行為型模式。在狀態(tài)模式中,我們創(chuàng)建對象表示各種狀態(tài),以及一個行為隨狀態(tài)改變而改變的上下文對象。
以下是一個狀態(tài)模式的示例。這個示例中,我們將創(chuàng)建一個銀行賬戶,它有兩個狀態(tài):正常狀態(tài)(NormalState)和透支狀態(tài)(OverdrawnState)。當(dāng)用戶執(zhí)行操作(存款和取款)時,賬戶狀態(tài)將相應(yīng)地進行更改。
首先,我們定義一個表示狀態(tài)的接口:
public interface IAccountState { void Deposit(Action addToBalance); void Withdraw(Action subtractFromBalance); void ComputeInterest(); }
然后,我們創(chuàng)建兩個表示具體狀態(tài)的類:
public class NormalState : IAccountState { public void Deposit(Action addToBalance) { addToBalance(); Console.WriteLine("Deposit in NormalState"); } public void Withdraw(Action subtractFromBalance) { subtractFromBalance(); Console.WriteLine("Withdraw in NormalState"); } public void ComputeInterest() { Console.WriteLine("Interest computed in NormalState"); } } public class OverdrawnState : IAccountState { public void Deposit(Action addToBalance) { addToBalance(); Console.WriteLine("Deposit in OverdrawnState"); } public void Withdraw(Action subtractFromBalance) { Console.WriteLine("No withdraw in OverdrawnState"); } public void ComputeInterest() { Console.WriteLine("Interest and fees computed in OverdrawnState"); } }
然后,我們創(chuàng)建一個Context類,它使用這些狀態(tài)來執(zhí)行其任務(wù):
public class BankAccount { private IAccountState _state; private double _balance; public BankAccount(IAccountState state) { _state = state; _balance = 0; } public void Deposit(double amount) { _state.Deposit(() => _balance += amount); StateChangeCheck(); } public void Withdraw(double amount) { _state.Withdraw(() => _balance -= amount); StateChangeCheck(); } public void ComputeInterest() { _state.ComputeInterest(); } private void StateChangeCheck() { if (_balance < 0.0) _state = new OverdrawnState(); else _state = new NormalState(); } }
現(xiàn)在,你可以創(chuàng)建一個實例并運行一個Demo來測試這個狀態(tài)模式的代碼:
public class Program { public static void Main(string[] args) { var account = new BankAccount(new NormalState()); account.Deposit(1000); // Deposit in NormalState account.Withdraw(2000); // Withdraw in NormalState; No withdraw in OverdrawnState account.Deposit(100); // Deposit in OverdrawnState account.ComputeInterest(); // Interest and fees computed in OverdrawnState Console.ReadKey(); } }
這個程序首先在正常狀態(tài)下進行存款操作,然后嘗試進行取款操作。由于取款金額超過賬戶余額,所以賬戶進入透支狀態(tài),并阻止進一步的取款操作。但存款仍然被允許,以使賬戶回歸到正常狀態(tài)。計算利息的行為也根據(jù)賬戶的狀態(tài)變化而變化。
8. 策略模式(Strategy)
策略模式定義了一系列的算法,并將每一個算法封裝起來,使得它們可以相互替換。策略模式讓算法獨立于使用它的客戶而獨立變化。
以下是一個簡單的策略模式的C#實現(xiàn)。這個例子中,我們將創(chuàng)建一個排序策略,比如快速排序和冒泡排序,它們實現(xiàn)同一個接口,然后創(chuàng)建一個Context類,它使用這些策略來執(zhí)行排序操作。
首先,我們定義一個表示排序策略的接口:
public interface ISortStrategy { void Sort(List<int> list); }
然后,我們創(chuàng)建兩個表示具體策略的類:
public class QuickSort : ISortStrategy { public void Sort(List<int> list) { list.Sort(); // Quick sort is in-place but here we are using built-in method Console.WriteLine("QuickSorted list "); } } public class BubbleSort : ISortStrategy { public void Sort(List<int> list) { int n = list.Count; for (int i = 0; i < n - 1; i++) for (int j = 0; j < n - i - 1; j++) if (list[j] > list[j + 1]) { // swap temp and list[i] int temp = list[j]; list[j] = list[j + 1]; list[j + 1] = temp; } Console.WriteLine("BubbleSorted list "); } }
然后,我們創(chuàng)建一個Context類,它使用這些策略來執(zhí)行其任務(wù):
public class SortedList { private List<int> _list = new List<int>(); private ISortStrategy _sortstrategy; public void SetSortStrategy(ISortStrategy sortstrategy) { this._sortstrategy = sortstrategy; } public void Add(int num) { _list.Add(num); } public void Sort() { _sortstrategy.Sort(_list); // Print sorted list foreach (int num in _list) { Console.Write(num + " "); } Console.WriteLine(); } }
現(xiàn)在,你可以創(chuàng)建一個實例并運行一個Demo來測試這個策略模式的代碼:
public class Program { public static void Main(string[] args) { SortedList sortedList = new SortedList(); sortedList.Add(1); sortedList.Add(5); sortedList.Add(3); sortedList.Add(4); sortedList.Add(2); sortedList.SetSortStrategy(new QuickSort()); sortedList.Sort(); // Output: QuickSorted list 1 2 3 4 5 sortedList.SetSortStrategy(new BubbleSort()); sortedList.Sort(); // Output: BubbleSorted list 1 2 3 4 5 Console.ReadKey(); } }
這個程序首先創(chuàng)建了一個未排序的列表,然后它首先使用快速排序策略進行排序,接著又使用冒泡排序策略進行排序。
9. 模板方法模式(Template Method)
模板方法模式定義了一個操作中算法的骨架,將這些步驟延遲到子類中。模板方法使得子類可以不改變算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
以下是一個模板方法模式的示例。這個示例中,我們將創(chuàng)建一個烹飪食物的過程,這個過程有一些固定的步驟(例如準(zhǔn)備材料,清理),但是具體的烹飪步驟則取決于具體的食物。
首先,我們定義一個抽象的模板類:
public abstract class CookingProcedure { // The 'Template method' public void PrepareDish() { PrepareIngredients(); Cook(); CleanUp(); } public void PrepareIngredients() { Console.WriteLine("Preparing the ingredients..."); } // These methods will be overridden by subclasses public abstract void Cook(); public void CleanUp() { Console.WriteLine("Cleaning up..."); } }
然后,我們創(chuàng)建兩個具體的子類,它們分別實現(xiàn)了具體的烹飪步驟:
public class CookPasta : CookingProcedure { public override void Cook() { Console.WriteLine("Cooking pasta..."); } } public class BakeCake : CookingProcedure { public override void Cook() { Console.WriteLine("Baking cake..."); } }
現(xiàn)在,你可以創(chuàng)建一個實例并運行一個Demo來測試這個模板方法模式的代碼:
public class Program { public static void Main(string[] args) { CookingProcedure cookingProcedure = new CookPasta(); cookingProcedure.PrepareDish(); Console.WriteLine(); cookingProcedure = new BakeCake(); cookingProcedure.PrepareDish(); Console.ReadKey(); } }
在這個程序中,我們首先創(chuàng)建了一個CookPasta
對象,然后調(diào)用其PrepareDish
方法。然后,我們創(chuàng)建了一個BakeCake
對象,再次調(diào)用其PrepareDish
方法。這兩個對象雖然具有不同的Cook
方法,但是它們的PrepareDish
方法的結(jié)構(gòu)(即算法的骨架)是相同的。
10. 訪問者模式(Visitor)
訪問者模式(Visitor Pattern)是一種將算法與對象結(jié)構(gòu)分離的軟件設(shè)計模式。這種模式的基本想法就是通過所謂的"訪問者"來改變元素的操作。這樣一來,元素的類可以用于表示元素結(jié)構(gòu),而具體的操作則可以在訪問者類中定義。
以下是一個使用C#實現(xiàn)的訪問者模式示例,包括了詳細的注釋和執(zhí)行流程。
這個示例中有三個主要部分:訪問者(IVisitor)、可訪問元素(IElement)和元素結(jié)構(gòu)(ObjectStructure)。同時有具體訪問者(ConcreteVisitor)和具體元素(ConcreteElement)。
// 訪問者接口 public interface IVisitor { void VisitConcreteElementA(ConcreteElementA concreteElementA); void VisitConcreteElementB(ConcreteElementB concreteElementB); } // 具體訪問者A public class ConcreteVisitorA : IVisitor { public void VisitConcreteElementA(ConcreteElementA concreteElementA) { Console.WriteLine($"{concreteElementA.GetType().Name} is being visited by {this.GetType().Name}"); } public void VisitConcreteElementB(ConcreteElementB concreteElementB) { Console.WriteLine($"{concreteElementB.GetType().Name} is being visited by {this.GetType().Name}"); } } // 具體訪問者B public class ConcreteVisitorB : IVisitor { public void VisitConcreteElementA(ConcreteElementA concreteElementA) { Console.WriteLine($"{concreteElementA.GetType().Name} is being visited by {this.GetType().Name}"); } public void VisitConcreteElementB(ConcreteElementB concreteElementB) { Console.WriteLine($"{concreteElementB.GetType().Name} is being visited by {this.GetType().Name}"); } } // 元素接口 public interface IElement { void Accept(IVisitor visitor); } // 具體元素A public class ConcreteElementA : IElement { public void Accept(IVisitor visitor) { visitor.VisitConcreteElementA(this); } } // 具體元素B public class ConcreteElementB : IElement { public void Accept(IVisitor visitor) { visitor.VisitConcreteElementB(this); } } // 對象結(jié)構(gòu) public class ObjectStructure { private List<IElement> _elements = new List<IElement>(); public void Attach(IElement element) { _elements.Add(element); } public void Detach(IElement element) { _elements.Remove(element); } public void Accept(IVisitor visitor) { foreach (var element in _elements) { element.Accept(visitor); } } }
執(zhí)行流程如下:
- 創(chuàng)建具體元素ConcreteElementA和ConcreteElementB的實例。
- 創(chuàng)建對象結(jié)構(gòu)ObjectStructure的實例,并將步驟1創(chuàng)建的具體元素添加到對象結(jié)構(gòu)中。
- 創(chuàng)建具體訪問者ConcreteVisitorA和ConcreteVisitorB的實例。
- 調(diào)用對象結(jié)構(gòu)的Accept方法,傳入步驟3創(chuàng)建的具體訪問者,使具體訪問者訪問對象結(jié)構(gòu)中的所有元素。
以下是一個使用上述代碼的示例:
public class Program { public static void Main() { ObjectStructure objectStructure = new ObjectStructure(); objectStructure.Attach(new ConcreteElementA()); objectStructure.Attach(new ConcreteElementB()); ConcreteVisitorA visitorA = new ConcreteVisitorA(); ConcreteVisitorB visitorB = new ConcreteVisitorB(); objectStructure.Accept(visitorA); objectStructure.Accept(visitorB); Console.ReadKey(); } }
這個程序會打印出訪問者A和訪問者B分別訪問具體元素A和具體元素B的信息。
以上就是C#實現(xiàn)23種常見的設(shè)計模式的示例詳解的詳細內(nèi)容,更多關(guān)于C#設(shè)計模式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C# Winform調(diào)用百度接口實現(xiàn)人臉識別教程(附源碼)
這篇文章主要介紹了C# Winform調(diào)用百度接口實現(xiàn)人臉識別教程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05C#實現(xiàn)通過模板自動創(chuàng)建Word文檔的方法
這篇文章主要介紹了C#實現(xiàn)通過模板自動創(chuàng)建Word文檔的方法,詳細講述了C#生成Word文檔的實現(xiàn)方法,是非常實用的技巧,需要的朋友可以參考下2014-09-09C#調(diào)用dos窗口獲取相關(guān)信息的方法
這篇文章主要介紹了C#調(diào)用dos窗口獲取相關(guān)信息的方法,涉及C#調(diào)用dos窗口及進程操作的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-08-08