デザインパターンは通常、3つの主要なカテゴリーに分類されます。
創造的パターン。
構造的モデル
行動パターンです。
これらのパターンは、一般的なオブジェクト指向設計の問題を解決するためのベストプラクティスです。
以下是 23 种常见的设计模式并且提供c#代码案例:
創造的なモデル:
1. シングルトン·モード
public sealed class Singleton
{
//创建一个只读的静态Singleton实例
private static readonly Singleton instance = new Singleton();
// 记录Singleton的创建次数
private static int instanceCounter = 0;
// 单例实例的公共访问点
public static Singleton Instance
{
get
{
return instance;
}
}
// 私有构造函数
private Singleton()
{
instanceCounter++;
Console.WriteLine("Instances Created " + instanceCounter);
}
// 在此处添加其他的Singleton类方法
public void LogMessage(string message)
{
Console.WriteLine("Message: " + message);
}
}
在这个例子中,我们有一个名为Singleton的类,它有一个私有的构造函数和一个静态的只读属性Instance,用于访问Singleton类的唯一实例。我们还有一个LogMessage方法,用于模拟Singleton类的某个行为。
以下是一个使用这个Singleton类的控制台应用程序:
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メソッドはクラスのインスタンス化をサブクラスに延期します。
C#で実装されたファクトリーメソッドパターンの簡単な例を以下に示します:
// 抽象产品
public interface IProduct
{
string Operation();
}
// 具体产品A
public class ProductA : IProduct
{
public string Operation()
{
return "{Result of ProductA}";
}
}
// 具体产品B
public class ProductB : IProduct
{
public string Operation()
{
return "{Result of ProductB}";
}
}
// 抽象创建者
public abstract class Creator
{
public abstract IProduct FactoryMethod();
}
// 具体创建者A
public class CreatorA : Creator
{
public override IProduct FactoryMethod()
{
return new ProductA();
}
}
// 具体创建者B
public class CreatorB : Creator
{
public override IProduct FactoryMethod()
{
return new ProductB();
}
}
以上代码中定义了两个产品ProductA和ProductB,这两个产品都实现了IProduct接口。接着我们有两个 Creator 类,CreatorA和CreatorB,它们都继承自抽象基类Creator。CreatorA工厂创建ProductA,CreatorB工厂创建ProductB。
これらのプラントと製品の使用例を以下に示します。
class Program
{
static void Main(string[] args)
{
// 创建工厂对象
Creator creatorA = new CreatorA();
Creator creatorB = new CreatorB();
// 通过工厂方法创建产品对象
IProduct productA = creatorA.FactoryMethod();
IProduct productB = creatorB.FactoryMethod();
// 打印结果
Console.WriteLine("ProductA says: " + productA.Operation());
Console.WriteLine("ProductB says: " + productB.Operation());
Console.ReadLine();
}
}
当你运行这个程序时,它会显示出ProductA和ProductB的Operation方法返回的结果。这说明我们已经成功地使用工厂方法模式创建了产品实例。每个工厂类决定了它创建哪个产品的实例。这种方式使得客户端代码不需要直接实例化产品类,而只需要依赖工厂接口,增加了程序的灵活性。
3. 抽象ファクトリ·パターン
抽象ファクトリーパターンは、オブジェクトの具体的なクラスを指定せずに、関連するオブジェクトや依存するオブジェクトのシリーズを作成するためのインターフェイスを提供する創造的デザインパターンです。このパターンでは、クライアントは抽象インターフェイスを介してクラスを使用し、クライアントに影響を与えることなく実装クラスを置き換えることができます。
以下は、C#での単純な抽象ファクトリーパターンの実装です:
// 抽象产品:动物
public interface IAnimal
{
string Speak();
}
// 具体产品:狗
public class Dog : IAnimal
{
public string Speak()
{
return "Bark Bark";
}
}
// 具体产品:猫
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,它们都实现了IAnimal接口。然后我们有两个工厂类,DogFactory和CatFactory,它们都继承自IAnimalFactory。DogFactory生产Dog,而CatFactory生产Cat。
これらのプラントと製品の使用例を以下に示します。
class Program
{
static void Main(string[] args)
{
// 创建工厂
IAnimalFactory dogFactory = new DogFactory();
IAnimalFactory catFactory = new CatFactory();
// 使用工厂创建产品
IAnimal dog = dogFactory.CreateAnimal();
IAnimal cat = catFactory.CreateAnimal();
// 打印结果
Console.WriteLine("Dog says: " + dog.Speak());
Console.WriteLine("Cat says: " + cat.Speak());
Console.ReadLine();
}
}
このプログラムを実行すると、DogとCatのSpeakメソッドの結果が出力され、Abstract Factoryパターンを使用して製品インスタンスを作成することができたことがわかります。このアプローチにより、クライアントコードは製品クラスを直接インスタンス化する必要がなく、ファクトリーインターフェイスに依存するだけで済み、プログラムの柔軟性と拡張性が向上します。
4. ビルダモード
ビルダーパターンは、オブジェクトを作成するためのインターフェイスを提供するクリエイティブデザインパターンですが、同じビルドプロセスを使用して異なる製品を作成することができます。
C#でビルダーパターンを実装する簡単な例を以下に示します:
// 产品
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是我们要创建的产品,CarBuilder是抽象的建造者,定义了制造一个产品所需要的各个步骤,FerrariBuilder是具体的建造者,实现了CarBuilder定义的所有步骤,Director是指挥者,它告诉建造者应该按照什么顺序去执行哪些步骤。
以下は、このビルダーパターンの使用例です。
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();
}
}
当你运行这个程序时,会看到我们已经成功地创建了一个Car实例,它的各个部分是按照FerrariBuilder所定义的方式创建的。这说明我们使用建造者模式成功地将一个复杂对象的构造过程解耦,使得同样的构造过程可以创建不同的表示。
5. プロトタイプモード
プロトタイプパターンは、現在のオブジェクトのクローンを作成するために使用されるプロトタイプインターフェイスを実装する作成型デザインパターンです。このパターンは、オブジェクトを直接作成するコストが高い場合に使用されます。例えば、オブジェクトは高価なデータベース操作の後に作成する必要があります。
C#でプロトタイプパターンを実装する簡単な例を以下に示します。
// 抽象原型
public interface IPrototype
{
IPrototype Clone();
}
// 具体原型
public class ConcretePrototype : IPrototype
{
public string Name { get; set; }
public int Value { get; set; }
public IPrototype Clone()
{
// 实现深拷贝
return (ConcretePrototype)this.MemberwiseClone(); // Clones the concrete object.
}
}
以上代码定义了一个ConcretePrototype类,它实现了IPrototype接口。接口定义了一个Clone方法,用于复制对象。在ConcretePrototype类中,我们使用了MemberwiseClone方法来创建一个新的克隆对象。
以下は、プロトタイプパターンの使用例です。
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();
}
}
在这个例子中,我们创建了一个ConcretePrototype对象,并为其属性赋值,然后我们调用Clone方法创建了一个新的ConcretePrototype对象。当我们运行这个程序时,会看到原始对象和克隆对象的属性是相同的,这表明我们已经成功地克隆了一个对象。
実行プロセスは以下の通り。
- プロパティに値を割り当てる具体的なプロトタイプオブジェクトを作成します。
- 调用原型对象的
Clone方法,创建一个新的对象,该对象的属性与原型对象的属性相同。 - プロトタイプオブジェクトとクローンオブジェクトのプロパティを印刷し、それらが同じであることを確認します。
構造的モデル:
1. アダプタモード
アダプタパターンAdapter Patternの目的は、あるクラスのインタフェースを、クライアントが期待する別のインタフェースに変換することです。アダプタは、インターフェイスの非互換性のために動作しないクラスを一緒に動作させます。C#で実装されたアダプターパターンの例を以下に示します:
在这个例子中,我将创建一个ITarget接口和一个Adaptee类。然后我将创建一个适配器Adapter,它会实现ITarget接口并使用Adaptee类的方法来满足ITarget的要求。
// 目标接口,或者客户端期望的接口。
public interface ITarget
{
string GetRequest();
}
// 需要适配的类。
public class Adaptee
{
public string GetSpecificRequest()
{
return "Specific request.";
}
}
// 适配器类,它通过在内部封装一个Adaptee对象来满足ITarget的接口。
public class Adapter : ITarget
{
private readonly Adaptee _adaptee;
public Adapter(Adaptee adaptee)
{
this._adaptee = adaptee;
}
public string GetRequest()
{
return $"This is '{this._adaptee.GetSpecificRequest()}'";
}
}
// 客户端代码,它与所有符合ITarget接口的对象兼容。
public class Client
{
public void MakeRequest(ITarget target)
{
Console.WriteLine(target.GetRequest());
}
}
実行プロセスは以下の通り。
class Program
{
static void Main(string[] args)
{
Adaptee adaptee = new Adaptee();
ITarget target = new Adapter(adaptee);
Client client = new Client();
// 由于适配器可以使得Adaptee与Client兼容,所以我们可以调用Client的MakeRequest方法
client.MakeRequest(target);
// 等待用户输入,以防止控制台程序立即退出。
Console.ReadKey();
}
}
上記のコードを実行すると、コンソールに次の出力が出力されます。
This is 'Specific request.'
此例中,Adapter是将Adaptee适配到ITarget接口的类。当客户端(在这种情况下是Client类)调用Adapter的GetRequest方法时,Adapter会将这个请求转发给Adaptee的GetSpecificRequest方法。
在此实例中,我们通过使用Adapter类,让原本接口不兼容的Client类和Adaptee类能够顺利地一起工作。
2. ブリッジモード
ブリッジパターンは、抽象部分と実装部分を分離し、それらを独立して変更できるようにするための構造設計パターンです。
C#でブリッジモードを実装する簡単な例を以下に示します。
// 实现类接口
public interface IImplementor
{
void OperationImp();
}
// 具体实现类A
public class ConcreteImplementorA : IImplementor
{
public void OperationImp()
{
Console.WriteLine("Concrete Implementor A");
}
}
// 具体实现类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接口的实例,通过这个实例调用实现类的方法。RefinedAbstraction是扩充的抽象类,它继承自Abstraction。ConcreteImplementorA和ConcreteImplementorB是实现类,它们实现了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();
}
}
在这个例子中,我们创建了两个实现类的实例,然后创建了两个抽象类的实例,每个抽象类的实例都有一个实现类的实例。当我们调用抽象类的Operation方法时,它会调用实现类的OperationImp方法。
実行プロセスは以下の通り。
- クラスを実装するインスタンスを作成します。
- 抽象クラスのインスタンスを作成します。抽象クラスのインスタンスは、クラスを実装するインスタンスを持ちます。
- 调用抽象类的
Operation方法,该方法会调用实现类的OperationImp方法。
3. コンポジットモード
コンポジットパターンは構造化されたデザインパターンで、オブジェクトをツリー構造にグループ化し、独立したオブジェクトと同じように使用できます。このパターンの主な目的は、個々のオブジェクトと複合オブジェクトの一貫性を維持することです。
C#でコンポジットパターンを実装する簡単な例を以下に示します。
// 抽象组件类
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);
}
// 叶节点类
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);
}
}
// 构件容器类
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);
// 显示每个节点的子节点
foreach (Component component in _children)
{
component.Display(depth + 2);
}
}
}
在这个代码中,Component是组件抽象类,它有一个名字,并定义了添加、删除和显示操作。Leaf是叶子节点,它实现了Component的操作。Composite是组件容器,它可以添加、删除和显示其子节点。
以下は、このパターンの使用例です:
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);
// 显示树形结构
root.Display(1);
Console.ReadLine();
}
}
この例では、ルートノードを作成し、そこに2つのリーフノードを追加しています。次に、複合ノードを作成し、そこに2つのリーフノードを追加し、複合ノードをルートノードに追加します。また、複合ノードに別の複合ノードを追加しました。最後に、ルートノードにリーフノードを追加したり削除したりして、ツリー構造を示します。
実行プロセスは以下の通り。
- コンポジションオブジェクトとリーフオブジェクトを作成します。
- 通过调用组合对象的
Add方法将叶子对象和其他组合对象添加到组合对象中。 - 通过调用组合对象的
Remove方法将叶子对象从组合对象中移除。 - 调用组合对象的
Display方法显示组合对象的结构。
4. デコレーションモード
Decorationパターンは、実行時にオブジェクトに機能を動的に追加できる構造化されたデザインパターンで、継承よりも柔軟なソリューションを提供します。
C#で装飾パターンを実装する簡単な例を以下に示します:
// 抽象组件
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是具体组件,它实现了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();
}
}
在这个例子中,我们首先创建了一个ConcreteComponent对象,并调用它的Operation方法。然后我们创建了一个ConcreteDecoratorA对象,它装饰了ConcreteComponent,并调用它的Operation方法。最后,我们创建了一个ConcreteDecoratorB对象,它装饰了ConcreteDecoratorA,并调用它的Operation方法。这样,我们就可以在运行时动态地添加功能。
実行プロセスは以下の通り。
- 具体的なコンポーネントオブジェクトを作成し、アクションを呼び出します。
- 具体的なコンポーネントを装飾するデコレータオブジェクトを作成し、そのアクションを呼び出します。アクションでは、デコレータは最初に特定のコンポーネントのアクションを呼び出し、その後追加のアクションを実行します。
- 別のDecoratorオブジェクトを作成し、前のDecoratorを装飾し、そのアクションを呼び出します。アクションでは、このデコレータは最初に前のデコレータのアクションを呼び出し、その後追加のアクションを実行します。
5. 外観モード
ファサードパターンは、サブシステム内のインターフェイスのセットにアクセスするための統一されたインターフェイスを提供する構造化デザインパターンです。ファサードパターンは、サブシステムを使いやすくする高レベルのインターフェイスを定義します。
C#での外観パターンの実装の簡単な例を以下に示します。
// 子系统A
public class SubSystemA
{
public string OperationA()
{
return "SubSystemA, OperationA\n";
}
}
// 子系统B
public class SubSystemB
{
public string OperationB()
{
return "SubSystemB, OperationB\n";
}
}
// 子系统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都是子系统,每个子系统都有一个操作。Facade是一个外观类,它封装了对子系统的操作,提供了一个统一的接口。
以下は、このパターンの使用例です:
class Program
{
static void Main(string[] args)
{
Facade facade = new Facade();
Console.WriteLine(facade.OperationWrapper());
Console.ReadLine();
}
}
在这个例子中,我们创建了一个Facade对象,并调用了它的OperationWrapper方法。这个方法封装了对子系统的操作,使得客户端可以不直接操作子系统,而是通过外观类操作子系统。
実行プロセスは以下の通り。
外観オブジェクトを作成する。
アピアランスオブジェクトのメソッドを呼び出すことでサブシステムを間接的に操作する.
サブシステムの操作は外観オブジェクトのメソッドにカプセル化され、クライアントはサブシステムを直接操作する必要はない。
6. 享元モード(Flyweight)
Flyweight Patternは、主に、メモリ消費量の削減とパフォーマンスの向上を目的として、作成するオブジェクトの数を減らすために使用される構造型デザインパターンです。このタイプのデザインパターンは構造化パターンであり、オブジェクトの数を減らしてアプリケーションに必要なオブジェクト構造を改善する方法を提供します。
以下はC#で共有パターンを実装する簡単な例です:
// 享元类
public class Flyweight
{
private string intrinsicState;
// 构造函数
public Flyweight(string intrinsicState)
{
this.intrinsicState = intrinsicState;
}
// 业务方法
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是享元类,它有一个内在状态intrinsicState,这个状态是不变的。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();
}
}
在这个例子中,我们创建了一个FlyweightFactory对象,并通过它创建了两个享元对象。注意,当我们试图创建第三个享元对象时,工厂实际上返回了第一个享元对象的引用,因为这两个对象的内在状态是相同的。
実行プロセスは以下の通り。
- 共有ファクトリーオブジェクトを作成します。
- 享元ファクトリーで享元オブジェクトを取得する。オブジェクトがすでに存在する場合は既存のオブジェクトを返し、それ以外の場合は新しいオブジェクトを作成します。
- 共有オブジェクトの操作を実行します。
- 現在のオブジェクトの数が表示されます。
7. プロキシモード
プロキシパターンは、あるオブジェクトを別のオブジェクトの代わりに提供し、そのオブジェクトへのアクセスを制御する構造化デザインパターンです。プロキシオブジェクトは、クライアントとターゲットオブジェクトの間の仲介として機能し、他の機能を追加することができる。
以下は、C#でプロキシパターンを実装する簡単な例です。
// 抽象主题接口
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()
{
// 检查是否有权限访问
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是实现了ISubject接口的类,Proxy是代理类,它也实现了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();
}
}
在这个例子中,我们首先直接调用了RealSubject的Request方法,然后我们通过代理调用了相同的方法。注意,在通过代理调用Request方法时,代理还执行了其他的操作,如检查访问权限和记录日志。
実行プロセスは以下の通り。
- 创建一个真实主题对象,并直接调用其
Request方法。 - 実際の主題への参照を含むプロキシオブジェクトを作成します。
- 通过代理对象调用
Request方法。在这个方法中,代理首先检查访问权限,然后调用真实主题的Request方法,最后记录日志。
行動パターン:
1. 責任連鎖モデルChain of Responsibility
責任の連鎖パターンChain of Responsibility Patternは、リクエストに対してオブジェクトを受け取るチェーンを作成する動作設計パターンです。このパターンは、要求されたオブジェクトにより自由度を与え、1つのオブジェクトがそれを処理するまでリクエストをリンクに沿って渡すことができます。
在这个例子中,我将创建一个Handler抽象类和两个具体的处理器ConcreteHandler1和ConcreteHandler2。每个处理器都检查它是否可以处理请求,如果可以,它就处理该请求。如果不行,它就将请求传递给链中的下一个处理器。
public abstract class Handler
{
protected Handler successor;
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
public abstract void HandleRequest(int request);
}
public class ConcreteHandler1 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 0 && request < 10)
{
Console.WriteLine($"{this.GetType().Name} handled request {request}");
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
public class ConcreteHandler2 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 10 && request < 20)
{
Console.WriteLine($"{this.GetType().Name} handled request {request}");
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
実行プロセスは以下の通り。
class Program
{
static void Main(string[] args)
{
// 设置责任链
Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHandler2();
h1.SetSuccessor(h2);
// 生成并处理请求
int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };
foreach (int request in requests)
{
h1.HandleRequest(request);
}
Console.ReadKey();
}
}
上記のコードを実行すると、コンソールに次の出力が出力されます。
ConcreteHandler1 handled request 2
ConcreteHandler1 handled request 5
ConcreteHandler2 handled request 14
ConcreteHandler2 handled request 18
ConcreteHandler1 handled request 3
在这个例子中,ConcreteHandler1和ConcreteHandler2都是处理器,它们决定是否处理传入的请求。如果ConcreteHandler1无法处理请求,它将请求传递给ConcreteHandler2。如果ConcreteHandler2也无法处理请求,那么请求就会被忽略。
この例は、リクエストを処理するためにオブジェクトのチェーンを作成する責任チェーンパターンのコアアイデアを示しています。このチェーン内では、各プロセッサがリクエストを処理するかどうかを決定します。リクエストを処理できない場合、チェーン内の次のプロセッサにリクエストを渡します。
2. コマンドモードCommand
コマンドパターンCommand Patternは、データ駆動型デザインパターンの一種であり、ビヘイビアパターンに属します。コマンドパターンでは、リクエストはオブジェクト内のアクションまたはアクションとしてカプセル化され、呼び出し元オブジェクトに送信され、呼び出し元オブジェクトはコマンドを処理できる適切なオブジェクトを探し、対応するオブジェクトに直接コマンドを送信し、それらを実行します。
C#でコマンドパターンを実装する簡単な例を以下に示します。
// 命令接口
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");
}
}
// 调用者或发送者类
public class Invoker
{
private ICommand command;
public void SetCommand(ICommand command)
{
this.command = command;
}
public void ExecuteCommand()
{
command.Execute();
}
}
在这个代码中,ICommand是命令接口,定义了Execute方法。ConcreteCommand是具体的命令类,它实现了ICommand接口,并持有一个Receiver对象的引用。Invoker是调用者或发送者类,它持有一个ICommand对象的引用,并可以通过SetCommand方法设置命令,通过ExecuteCommand方法执行命令。
以下は、このパターンの使用例です:
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();
}
}
在这个例子中,我们创建了一个Receiver对象、一个ConcreteCommand对象和一个Invoker对象。然后我们通过Invoker的SetCommand方法设置了命令,并通过ExecuteCommand方法执行了命令。
実行プロセスは以下の通り。
- 受信者オブジェクトを作成します。
- 具体的なコマンドオブジェクトを作成し、それに受信者オブジェクトを渡します。
- 呼び出し元または送信元オブジェクトを作成します。
- 通过调用者对象的
SetCommand方法设置命令。 - 通过调用者对象的
ExecuteCommand方法执行命令。
3. インタプリタ·モード
インタプリタパターンInterpreter Patternは、いくつかの固定された構文フォーマットのニーズに対処するためのビヘイビア型デザインパターンです。言語における構文の表現と解析の方法を定義します。
C#でインタプリタパターンを実装する簡単な例を以下に示します。
// 抽象表达式
public interface IExpression
{
bool Interpret(string context);
}
// 终结符表达式
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;
}
}
// 非终结符表达式
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是终结符表达式,它实现了IExpression接口。OrExpression是非终结符表达式,它也实现了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();
}
// 规则:Robert 和 John 是男性
public static IExpression GetMaleExpression()
{
IExpression robert = new TerminalExpression("Robert");
IExpression john = new TerminalExpression("John");
return new OrExpression(robert, john);
}
// 规则:Julie 是一个已婚的女性
public static IExpression GetMarriedWomanExpression()
{
IExpression julie = new TerminalExpression("Julie");
IExpression married = new TerminalExpression("Married");
return new OrExpression(julie, married);
}
}
この例では、“ロバートとジョンは男性である”と“ジュリーは既婚女性である”という2つのルールを定義しています。次に、これら2つのルールを表す2つの式オブジェクトを作成し、両方のオブジェクトを使用して入力を解析します。
実行プロセスは以下の通り。
- 規則を表現するために使用される終端記号式オブジェクトと非終端記号式オブジェクトを作成します。
- 调用表达式对象的
Interpret方法,解析输入的字符串。 - 解析結果の出力。
4. イテレータ·モード
イテレータパターンIterator Patternは、オブジェクトの内部表現を公開することなく、オブジェクトの要素にアクセスする方法を提供するビヘイビア型デザインパターンの一種です。以下はC#でイテレータパターンを実装する簡単な例です:
// 抽象聚合类
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是具体聚合类,实现了IAggregate接口。IIterator是抽象迭代器,定义了First、Next等方法,ConcreteIterator是具体迭代器,实现了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();
}
}
在这个例子中,我们创建了一个ConcreteAggregate对象,并添加了几个元素。然后我们通过CreateIterator方法创建了一个迭代器,并使用这个迭代器遍历了集合中的所有元素。
実行プロセスは以下の通り。
- 集約オブジェクトを作成し、要素を追加します。
- 通过聚合对象的
CreateIterator方法创建一个迭代器。 - 通过迭代器的
First方法获取第一个元素,然后通过Next方法获取后续的元素,直到获取不到元素为止。
5. メディエーターモード
メディエーターパターンは、オブジェクトのグループ間の複雑な通信を減らすことを可能にする行動設計パターンです。これらのオブジェクトが直接通信するのではなく、グループ内のオブジェクト間の通信を担当する仲介者オブジェクトを提供します。
まず、メディエーターインターフェイスと具体的なメディエーターを定義しましょう:
// Mediator 接口声明了与组件交互的方法。
public interface IMediator
{
void Notify(object sender, string ev);
}
// 具体 Mediators 实现协作行为,它负责协调多个组件。
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();
}
}
}
次に、基本コンポーネントクラスと2つの具体コンポーネントを定義します。
public abstract class BaseComponent
{
protected IMediator _mediator;
public BaseComponent(IMediator mediator = null)
{
_mediator = mediator;
}
public void SetMediator(IMediator mediator)
{
this._mediator = mediator;
}
}
// 具体 Components 实现各种功能。它们不依赖于其他组件。
// 它们也不依赖于任何具体 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");
}
}
最後に、クライアントコードを作成しましょう:
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();
}
}
この例では、コンポーネントは直接ではなく仲介者を介して通信するため、コンポーネント間の依存関係が少なくなり、独立して変更が容易になります。あるコンポーネントで何らかのイベントが発生すると(例:“Component 1 does A”)、仲介者を介して他のコンポーネントに通知し、他のコンポーネントがそのイベントに応じて応答できるようにします(例:“Component 2 does C”)。
6. メモモードMemento
メモパターンは、オブジェクトの状態を保存し、後で復元できるようにするビヘイビアデザインパターンです。ほとんどの場合、このパターンを使用すると、オブジェクトのカプセル化を破壊することなくオブジェクトの履歴状態を保存および復元できます。
以下是一个简单的备忘录模式的实现,其中有三个主要的类:Originator(保存了一个重要的状态,这个状态可能会随着时间改变),Memento(保存了Originator的一个快照,这个快照包含了Originator的状态),以及Caretaker(负责保存Memento)。
// Originator 类可以生成一个备忘录,并且可以通过备忘录恢复其状态。
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}");
}
}
// 备忘录接口提供了获取备忘录和原发器状态的方法。但在该接口中并未声明所有的方法,一些方法只在原发器中声明。
public interface IMemento
{
string GetName();
string GetState();
DateTime GetDate();
}
// Concrete Memento 存储原发器状态,并通过原发器实现备份。备忘录是不可变的,因此,没有 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 不依赖于具体备忘录类。结果,它不会有任何访问原发器状态的权利,它只能获取备忘录的元数据。
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はいくつかの重要な状態を保持しており、その状態をメモオブジェクトに保存したり、メモオブジェクトから状態を復元したりする方法を提供しています。Caretakerはメモを保存しますが、メモオブジェクト内の状態を操作することはできません。ユーザーがアクションを実行すると、まず現在の状態を保存してからアクションを実行します。ユーザーが後で新しい状態に満足しない場合、古いメモから状態を簡単に復元できます。
7. オブザーバ·モード
オブザーバパターンObserver Patternは、あるオブジェクトの状態が変化すると、それに依存するすべてのオブジェクトに通知され、自動的に更新されるビヘイビア型デザインパターンです。以下は、C#でObserverパターンを実装する簡単な例です:
// 抽象观察者
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()
{
// 触发状态变化,通知所有观察者
NotifyObservers();
}
}
在这个代码中,IObserver是抽象观察者,定义了Update方法,ConcreteObserver是具体观察者,实现了IObserver接口。ISubject是抽象主题,定义了RegisterObserver、RemoveObserver和NotifyObservers方法,ConcreteSubject是具体主题,实现了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();
}
}
在这个例子中,我们创建了一个ConcreteSubject对象,并注册了三个观察者。然后我们通过ChangeState方法改变了主题的状态,这会触发主题通知所有观察者。
実行プロセスは以下の通り。
- 特定のトピックオブジェクトを作成します。
- 创建几个具体观察者对象,并通过主题的
RegisterObserver方法将这些观察者注册到主题中。 - 通过主题的
ChangeState方法改变主题的状态,这会触发主题通知所有观察者。
8. 状態モード
ステートパターンは、オブジェクト指向プログラミングにおいて、オブジェクトの内部状態が変化したときにその振る舞いを変更できるようにするデザインパターンである。このタイプのデザインパターンは行動パターンに属します。ステートモードでは、さまざまなステートを表すオブジェクトと、ステートの変化に応じて振る舞いが変化するコンテキストオブジェクトを作成します。
以下は、ステートパターンの例です。この例では、通常状態NormalStateと当座貸越状態OverdrawnStateの2つの状態を持つ銀行口座を作成します。ユーザーが操作(入出金)を行うと、それに応じてアカウントの状態が変更されます。
まず、状態を表すインターフェイスを定義します。
public interface IAccountState
{
void Deposit(Action addToBalance);
void Withdraw(Action subtractFromBalance);
void ComputeInterest();
}
次に、特定の状態を表す2つのクラスを作成します。
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");
}
}
次に、これらの状態を使用してタスクを実行するContextクラスを作成します。
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();
}
}
これで、インスタンスを作成してデモを実行して、このステートパターンのコードをテストできます。
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();
}
}
このプログラムは、まず通常の状態で入金操作を行い、次に引き出し操作を試みます。出金金額が口座残高を上回るため、口座は当座貸越状態になり、更なる出金操作が阻止される。ただし、預金は口座を正常に戻すために許可されます。利息を計算する行為も、口座の状態によって変化します。
9. ストラテジー·モード
ポリシーパターンは一連のアルゴリズムを定義し、それぞれを互いに置き換えることができるようにカプセル化する。ポリシーパターンは、アルゴリズムを使用する顧客とは独立して変化させる。
以下は、C#の簡単なポリシーパターンの実装です。この例では、同じインターフェイスを実装するクイックソートやバブルソートなどのソート戦略を作成し、これらの戦略を使用してソート操作を実行するContextクラスを作成します。
まず、ソートポリシーを表すインターフェイスを定義します:
public interface ISortStrategy
{
void Sort(List<int> list);
}
次に、具体的な戦略を表す2つのクラスを作成します。
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 ");
}
}
次に、以下のポリシーを使用してタスクを実行するContextクラスを作成します。
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();
}
}
これで、インスタンスを作成してデモを実行して、この戦略パターンのコードをテストできます。
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();
}
}
このプログラムは、最初にソートされていないリストを作成し、次にクイックソート戦略を使用してソートし、次にバブルソート戦略を使用してソートします。
10. テンプレートメソッドパターン
テンプレートメソッドパターンは、アクション内のアルゴリズムのスケルトンを定義し、これらのステップをサブクラスに延期します。テンプレートメソッドは、サブクラスがアルゴリズムの構造を変更せずに特定のステップを再定義できるようにする。
テンプレートメソッドパターンの例を以下に示します。この例では、いくつかの固定されたステップ(材料の準備、清掃など)を持つ食品を調理するプロセスを作成しますが、調理ステップは特定の食品に依存します。
まず、抽象テンプレートクラスを定義します。
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...");
}
}
次に、特定の調理手順を実装する2つの具体的なサブクラスを作成します。
public class CookPasta : CookingProcedure
{
public override void Cook()
{
Console.WriteLine("Cooking pasta...");
}
}
public class BakeCake : CookingProcedure
{
public override void Cook()
{
Console.WriteLine("Baking cake...");
}
}
これで、インスタンスを作成してデモを実行して、このテンプレートメソッドパターンのコードをテストできます。
public class Program
{
public static void Main(string[] args)
{
CookingProcedure cookingProcedure = new CookPasta();
cookingProcedure.PrepareDish();
Console.WriteLine();
cookingProcedure = new BakeCake();
cookingProcedure.PrepareDish();
Console.ReadKey();
}
}
在这个程序中,我们首先创建了一个CookPasta对象,然后调用其PrepareDish方法。然后,我们创建了一个BakeCake对象,再次调用其PrepareDish方法。这两个对象虽然具有不同的Cook方法,但是它们的PrepareDish方法的结构(即算法的骨架)是相同的。
11. ビジタモード
ビジターパターンVisitor Patternは、アルゴリズムとオブジェクト構造を分離するソフトウェア設計パターンである。このパターンの基本的な考え方は、いわゆる“訪問者”によって要素の操作を変更することです。このようにして、要素のクラスは要素構造を表現するために使用でき、具体的な操作はビジタークラスで定義できます。
以下は、C#で実装されたビジターパターンの例で、詳細なコメントと実行フローを含んでいます。
この例には、ビジター IVisitor、アクセス可能要素IElement、要素構造ObjectStructureの3つの主要部分があります。“コンクリテビジター”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);
}
}
// 对象结构
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);
}
}
}
実行プロセスは以下の通り。
- ConcreteElementAとConcreteElementBのインスタンスを作成します。
- オブジェクト構造ObjectStructureのインスタンスを作成し、手順1で作成した具体的な要素をオブジェクト構造に追加します。
- ConcreteVisitor AとConcreteVisitor Bのインスタンスを作成します。
- オブジェクト構造のAcceptメソッドを呼び出し、ステップ3で作成した具体的なビジターを渡し、オブジェクト構造内のすべての要素にアクセスできるようにします。
上記のコードを使用した例を以下に示します。
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にアクセスした情報を出力します。
技術交流のプロセス
NET Coreコミュニケーショングループ:73777659 5
トークンからの共有