C# Language
創造的なデザインパターン
サーチ…
備考
創造的なパターンは、システムを、そのオブジェクトがどのように創造され、構成され、表現されているかから分離することを目指しています。それらは、オブジェクトの作成の対象、対象、方法、時期について、システムの柔軟性を向上させます。作成パターンは、システムが使用するクラスに関する知識をカプセル化しますが、これらのクラスのインスタンスがどのように作成され、まとめられているかの詳細を隠します。プログラマーは、継承を持つシステムを構成することは、それらのシステムをあまりにも硬直させることに気付くようになった。創造的なパターンは、この密接な結合を破るように設計されています。
シングルトンパターン
シングルトンパターンは、クラスの作成を厳密に1つの単一インスタンスに制限するように設計されています。
このパターンは、次のようなものが1つしかないのが理にかなっているシナリオで使用されます。
- 他のオブジェクトの相互作用を調整する単一のクラス、例。マネージャークラス
- 一意の単一リソースを表す1つのクラス、例えば、ロギングコンポーネント
Singletonパターンを実装する最も一般的な方法の1つは、 CreateInstance()
やGetInstance()
(またはC#、 Instance
静的プロパティGetInstance()
などの静的ファクトリメソッドを使用し、常に同じインスタンスを返すように設計されています。
メソッドまたはプロパティへの最初の呼び出しは、Singletonインスタンスを作成して返します。その後、メソッドは常に同じインスタンスを返します。このようにして、シングルトンオブジェクトのインスタンスは1つしかありません。
クラスコンストラクタをprivate.
することで、 new
を使用したインスタンスの作成を防ぐことができますprivate.
C#でシングルトンパターンを実装するための典型的なコード例を次に示します。
class Singleton
{
// Because the _instance member is made private, the only way to get the single
// instance is via the static Instance property below. This can also be similarly
// achieved with a GetInstance() method instead of the property.
private static Singleton _instance = null;
// Making the constructor private prevents other instances from being
// created via something like Singleton s = new Singleton(), protecting
// against unintentional misuse.
private Singleton()
{
}
public static Singleton Instance
{
get
{
// The first call will create the one and only instance.
if (_instance == null)
{
_instance = new Singleton();
}
// Every call afterwards will return the single instance created above.
return _instance;
}
}
}
このパターンをさらに説明するために、以下のコードでは、Instanceプロパティが複数回呼び出されたときに、Singletonの同一インスタンスが返されるかどうかを確認します。
class Program
{
static void Main(string[] args)
{
Singleton s1 = Singleton.Instance;
Singleton s2 = Singleton.Instance;
// Both Singleton objects above should now reference the same Singleton instance.
if (Object.ReferenceEquals(s1, s2))
{
Console.WriteLine("Singleton is working");
}
else
{
// Otherwise, the Singleton Instance property is returning something
// other than the unique, single instance when called.
Console.WriteLine("Singleton is broken");
}
}
}
注:この実装はスレッドセーフではありません。
このスレッドセーフな方法を含む、より多くの例を見るには、次をご覧ください: Singleton Implementation
シングルトンは概念的にはグローバル値に類似しており、同様の設計上の欠陥や懸念を引き起こします。このため、シングルトンパターンは広く反パターンと見なされます。
「シングルトンについて何が悪いの?」使用時に発生する問題の詳細については、こちらを参照してください。
C#では、クラスをstatic
にすることができます。これにより、すべてのメンバーが静的になり、クラスをインスタンス化できなくなります。これを考えると、シングルトンパターンの代わりに使用される静的クラスを見るのが一般的です。
両者の主な違いについては、「 C#Singleton Pattern vs. Static Class」を参照してください 。
ファクトリメソッドパターン
ファクトリメソッドは、創造的なデザインパターンの1つです。これは、正確な結果タイプを指定せずにオブジェクトを作成するという問題に対処するために使用されます。このドキュメントでは、ファクトリメソッドDPを正しく使用する方法について説明します。
あなたに簡単な例でそれのアイデアを説明しましょう。電流計、電圧計、抵抗計の3種類のデバイスを製造する工場で働いているとします。あなたは、選択されたデバイスを作成する中央コンピュータ用のプログラムを作成していますが、あなたは何を生産するかについて上司の最終決定を知らないのです。
すべてのデバイスに共通の機能を持つインターフェースIDevice
を作成しましょう。
public interface IDevice
{
int Measure();
void TurnOff();
void TurnOn();
}
さて、私たちのデバイスを表すクラスを作成することができます。それらのクラスはIDevice
インタフェースを実装する必要があります:
public class AmMeter : IDevice
{
private Random r = null;
public AmMeter()
{
r = new Random();
}
public int Measure() { return r.Next(-25, 60); }
public void TurnOff() { Console.WriteLine("AmMeter flashes lights saying good bye!"); }
public void TurnOn() { Console.WriteLine("AmMeter turns on..."); }
}
public class OhmMeter : IDevice
{
private Random r = null;
public OhmMeter()
{
r = new Random();
}
public int Measure() { return r.Next(0, 1000000); }
public void TurnOff() { Console.WriteLine("OhmMeter flashes lights saying good bye!"); }
public void TurnOn() { Console.WriteLine("OhmMeter turns on..."); }
}
public class VoltMeter : IDevice
{
private Random r = null;
public VoltMeter()
{
r = new Random();
}
public int Measure() { return r.Next(-230, 230); }
public void TurnOff() { Console.WriteLine("VoltMeter flashes lights saying good bye!"); }
public void TurnOn() { Console.WriteLine("VoltMeter turns on..."); }
}
ここでファクトリメソッドを定義する必要があります。静的メソッドを内部に持つDeviceFactory
クラスを作成しましょう:
public enum Device
{
AM,
VOLT,
OHM
}
public class DeviceFactory
{
public static IDevice CreateDevice(Device d)
{
switch(d)
{
case Device.AM: return new AmMeter();
case Device.VOLT: return new VoltMeter();
case Device.OHM: return new OhmMeter();
default: return new AmMeter();
}
}
}
すばらしいです!私たちのコードをテストしましょう:
public class Program
{
static void Main(string[] args)
{
IDevice device = DeviceFactory.CreateDevice(Device.AM);
device.TurnOn();
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
device.TurnOff();
Console.WriteLine();
device = DeviceFactory.CreateDevice(Device.VOLT);
device.TurnOn();
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
device.TurnOff();
Console.WriteLine();
device = DeviceFactory.CreateDevice(Device.OHM);
device.TurnOn();
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
device.TurnOff();
Console.WriteLine();
}
}
これは、このコードを実行した後に表示される出力の例です。
AmMeterがオンになります...
36
6
33
43
24
AmMeterは、さようならと言って光を点滅させます!
VoltMeterがオンになります...
102
-61
85
138
36
VoltMeterがライトを点滅させ、さよならを言っている!
OhmMeterがオンになります...
723828
368536
685412
800266
578595
OhmMeterは、さようならを言っている光を点滅させる!
ビルダーパターン
複雑なオブジェクトの構成をその表現から分離して、同じ構築プロセスで異なる表現を作成し、オブジェクトのアセンブリを高いレベルで制御できるようにします。
この例では、さまざまな車両が段階的に組み立てられたBuilderパターンを示しています。ショップでは、VehicleBuildersを使用して一連の順次ステップでさまざまなビークルを構築しています。
using System;
using System.Collections.Generic;
namespace GangOfFour.Builder
{
/// <summary>
/// MainApp startup class for Real-World
/// Builder Design Pattern.
/// </summary>
public class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
public static void Main()
{
VehicleBuilder builder;
// Create shop with vehicle builders
Shop shop = new Shop();
// Construct and display vehicles
builder = new ScooterBuilder();
shop.Construct(builder);
builder.Vehicle.Show();
builder = new CarBuilder();
shop.Construct(builder);
builder.Vehicle.Show();
builder = new MotorCycleBuilder();
shop.Construct(builder);
builder.Vehicle.Show();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Director' class
/// </summary>
class Shop
{
// Builder uses a complex series of steps
public void Construct(VehicleBuilder vehicleBuilder)
{
vehicleBuilder.BuildFrame();
vehicleBuilder.BuildEngine();
vehicleBuilder.BuildWheels();
vehicleBuilder.BuildDoors();
}
}
/// <summary>
/// The 'Builder' abstract class
/// </summary>
abstract class VehicleBuilder
{
protected Vehicle vehicle;
// Gets vehicle instance
public Vehicle Vehicle
{
get { return vehicle; }
}
// Abstract build methods
public abstract void BuildFrame();
public abstract void BuildEngine();
public abstract void BuildWheels();
public abstract void BuildDoors();
}
/// <summary>
/// The 'ConcreteBuilder1' class
/// </summary>
class MotorCycleBuilder : VehicleBuilder
{
public MotorCycleBuilder()
{
vehicle = new Vehicle("MotorCycle");
}
public override void BuildFrame()
{
vehicle["frame"] = "MotorCycle Frame";
}
public override void BuildEngine()
{
vehicle["engine"] = "500 cc";
}
public override void BuildWheels()
{
vehicle["wheels"] = "2";
}
public override void BuildDoors()
{
vehicle["doors"] = "0";
}
}
/// <summary>
/// The 'ConcreteBuilder2' class
/// </summary>
class CarBuilder : VehicleBuilder
{
public CarBuilder()
{
vehicle = new Vehicle("Car");
}
public override void BuildFrame()
{
vehicle["frame"] = "Car Frame";
}
public override void BuildEngine()
{
vehicle["engine"] = "2500 cc";
}
public override void BuildWheels()
{
vehicle["wheels"] = "4";
}
public override void BuildDoors()
{
vehicle["doors"] = "4";
}
}
/// <summary>
/// The 'ConcreteBuilder3' class
/// </summary>
class ScooterBuilder : VehicleBuilder
{
public ScooterBuilder()
{
vehicle = new Vehicle("Scooter");
}
public override void BuildFrame()
{
vehicle["frame"] = "Scooter Frame";
}
public override void BuildEngine()
{
vehicle["engine"] = "50 cc";
}
public override void BuildWheels()
{
vehicle["wheels"] = "2";
}
public override void BuildDoors()
{
vehicle["doors"] = "0";
}
}
/// <summary>
/// The 'Product' class
/// </summary>
class Vehicle
{
private string _vehicleType;
private Dictionary<string,string> _parts =
new Dictionary<string,string>();
// Constructor
public Vehicle(string vehicleType)
{
this._vehicleType = vehicleType;
}
// Indexer
public string this[string key]
{
get { return _parts[key]; }
set { _parts[key] = value; }
}
public void Show()
{
Console.WriteLine("\n---------------------------");
Console.WriteLine("Vehicle Type: {0}", _vehicleType);
Console.WriteLine(" Frame : {0}", _parts["frame"]);
Console.WriteLine(" Engine : {0}", _parts["engine"]);
Console.WriteLine(" #Wheels: {0}", _parts["wheels"]);
Console.WriteLine(" #Doors : {0}", _parts["doors"]);
}
}
}
出力
車両のタイプ:スクーターフレーム:スクーターフレーム
エンジン:なし
#ホイール:2
#Doors:0車種:車
フレーム:車のフレーム
エンジン:2500 cc
#ホイール:4
#Doors:4車両の種類:MotorCycle
フレーム:モーターサイクルフレーム
エンジン:500 cc
#ホイール:2
#Doors:0
プロトタイプパターン
プロトタイプのインスタンスを使用して作成するオブジェクトの種類を指定し、このプロトタイプをコピーして新しいオブジェクトを作成します。
この例では、同じタイプの既存のユーザー定義の色をコピーして新しいColorオブジェクトを作成するプロトタイプパターンを示します。
using System;
using System.Collections.Generic;
namespace GangOfFour.Prototype
{
/// <summary>
/// MainApp startup class for Real-World
/// Prototype Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
ColorManager colormanager = new ColorManager();
// Initialize with standard colors
colormanager["red"] = new Color(255, 0, 0);
colormanager["green"] = new Color(0, 255, 0);
colormanager["blue"] = new Color(0, 0, 255);
// User adds personalized colors
colormanager["angry"] = new Color(255, 54, 0);
colormanager["peace"] = new Color(128, 211, 128);
colormanager["flame"] = new Color(211, 34, 20);
// User clones selected colors
Color color1 = colormanager["red"].Clone() as Color;
Color color2 = colormanager["peace"].Clone() as Color;
Color color3 = colormanager["flame"].Clone() as Color;
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Prototype' abstract class
/// </summary>
abstract class ColorPrototype
{
public abstract ColorPrototype Clone();
}
/// <summary>
/// The 'ConcretePrototype' class
/// </summary>
class Color : ColorPrototype
{
private int _red;
private int _green;
private int _blue;
// Constructor
public Color(int red, int green, int blue)
{
this._red = red;
this._green = green;
this._blue = blue;
}
// Create a shallow copy
public override ColorPrototype Clone()
{
Console.WriteLine(
"Cloning color RGB: {0,3},{1,3},{2,3}",
_red, _green, _blue);
return this.MemberwiseClone() as ColorPrototype;
}
}
/// <summary>
/// Prototype manager
/// </summary>
class ColorManager
{
private Dictionary<string, ColorPrototype> _colors =
new Dictionary<string, ColorPrototype>();
// Indexer
public ColorPrototype this[string key]
{
get { return _colors[key]; }
set { _colors.Add(key, value); }
}
}
}
出力:
クローニング色RGB:255,0,0
クローニングカラーRGB:128,211,128
クローニング色RGB:211,34,20
抽象的な工場パターン
具体的なクラスを指定せずに、関連オブジェクトまたは依存オブジェクトのファミリを作成するためのインタフェースを提供します。
この例では、異なる工場を使用するコンピュータゲームのための異なる動物の世界の創造を示す。大陸工場によって作られた動物は異なるが、動物間の相互作用は同じままである。
using System;
namespace GangOfFour.AbstractFactory
{
/// <summary>
/// MainApp startup class for Real-World
/// Abstract Factory Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
public static void Main()
{
// Create and run the African animal world
ContinentFactory africa = new AfricaFactory();
AnimalWorld world = new AnimalWorld(africa);
world.RunFoodChain();
// Create and run the American animal world
ContinentFactory america = new AmericaFactory();
world = new AnimalWorld(america);
world.RunFoodChain();
// Wait for user input
Console.ReadKey();
}
}
/// <summary>
/// The 'AbstractFactory' abstract class
/// </summary>
abstract class ContinentFactory
{
public abstract Herbivore CreateHerbivore();
public abstract Carnivore CreateCarnivore();
}
/// <summary>
/// The 'ConcreteFactory1' class
/// </summary>
class AfricaFactory : ContinentFactory
{
public override Herbivore CreateHerbivore()
{
return new Wildebeest();
}
public override Carnivore CreateCarnivore()
{
return new Lion();
}
}
/// <summary>
/// The 'ConcreteFactory2' class
/// </summary>
class AmericaFactory : ContinentFactory
{
public override Herbivore CreateHerbivore()
{
return new Bison();
}
public override Carnivore CreateCarnivore()
{
return new Wolf();
}
}
/// <summary>
/// The 'AbstractProductA' abstract class
/// </summary>
abstract class Herbivore
{
}
/// <summary>
/// The 'AbstractProductB' abstract class
/// </summary>
abstract class Carnivore
{
public abstract void Eat(Herbivore h);
}
/// <summary>
/// The 'ProductA1' class
/// </summary>
class Wildebeest : Herbivore
{
}
/// <summary>
/// The 'ProductB1' class
/// </summary>
class Lion : Carnivore
{
public override void Eat(Herbivore h)
{
// Eat Wildebeest
Console.WriteLine(this.GetType().Name +
" eats " + h.GetType().Name);
}
}
/// <summary>
/// The 'ProductA2' class
/// </summary>
class Bison : Herbivore
{
}
/// <summary>
/// The 'ProductB2' class
/// </summary>
class Wolf : Carnivore
{
public override void Eat(Herbivore h)
{
// Eat Bison
Console.WriteLine(this.GetType().Name +
" eats " + h.GetType().Name);
}
}
/// <summary>
/// The 'Client' class
/// </summary>
class AnimalWorld
{
private Herbivore _herbivore;
private Carnivore _carnivore;
// Constructor
public AnimalWorld(ContinentFactory factory)
{
_carnivore = factory.CreateCarnivore();
_herbivore = factory.CreateHerbivore();
}
public void RunFoodChain()
{
_carnivore.Eat(_herbivore);
}
}
}
出力:
ライオンはワイルドビーストを食べる
オオカミはバイソンを食べる