[C#][デザインパターン] Iteratorパターン

オブジェクトAとオブジェクトBがあり、オブジェクトBが持つ配列をオブジェクトAの中でforを使用して取り出すことを考えてみましょう。

オブジェクトBの配列をオブジェクトAから操作する

この場合、オブジェクトAは以下のことを知っている必要があります。

  • オブジェクトBが持つデータの構造が配列であること
  • 配列の名前や先頭の要素番号や末尾の要素番号

もし、オブジェクトAの中で、読み取る配列のインデックス番号を間違えてしまったらエラーになってしまいます。

また、オブジェクトBのデータが配列からリストやスタックといったデータ構造に変更されてしまった場合には、オブジェクトAを書き換える必要が生じます。

この問題を解決するためにIteratorパターンを使用します。

Iteratorパターンは、

  • オブジェクトが持つデータの構造は非公開にする
  • オブジェクトがデータを持っているかどうかをhasNextメソッドで表す。
  • オブジェクトの取り出しはnextメソッドを介して行う

という特徴があります。

最初にhasNextメソッドとnextメソッドを持つインターフェースを定義します。

C#の例

interface IIterator
{
    bool hasNext();
    string next();
}

次に上記で作成したインターフェースを持つConcreatAggregateクラスを定義します。

class ConcreatAggregate : IIterator
{
    private List<string> aggregate = new List<string>();
    private int _nextIndex = 0;

    /// <summary>
    /// 要素の追加
    /// </summary>
    /// <param name="item"></param>
    public void addItem(string item)
    {
        aggregate.Add(item);
    }

    /// <summary>
    /// 次のアイテムがある場合はtrue
    /// </summary>
    /// <returns></returns>
    public bool hasNext()
    {
        return this._nextIndex < this.length;
    }

    /// <summary>
    /// 次のアイテムを取得
    /// </summary>
    /// <returns></returns>
    public string next()
    {
        return aggregate[this._nextIndex++];
    }

    /// <summary>
    /// 要素数
    /// </summary>
    public int length 
    { 
        get
        {
            return this.aggregate.Count;
        }

    }
}

以上でIteratorパターンの実装は完了です。

あとは実際にConcreateAggregateクラスを使用してみます。

while文の条件で hasNextメソッドを使用し、次のアイテムがある間はループをします。

このようにIteratorパターンを使用すると、要素数がいくつあるかを気にすることなく順番に取り出すことが可能です。

static void Main(string[] args)
{
    ConcreatAggregate agr = new ConcreatAggregate();
    agr.addItem("test1");
    agr.addItem("test2");
    agr.addItem("test3");

    // 次のアイテムがある間はループする
    while (agr.hasNext())
    {
        // アイテムを取り出して表示
        Console.WriteLine(agr.next());
    }
}

[C#][デザインパターン] Facadeパターン

今回はFacadeパターンについて見ていきます。

クラスA、クラスB、クラスCという3つのクラスがあり、ある機能を実現するためにはすべてのクラスを利用する必要があるとします。

3つのクラスを利用するのは面倒なので、3つのクラスを利用するクラスDを作成します。

クラスDのように複数のクラスをひとまとめにしたものを「Facadeクラス」と呼び、Facadeクラスを使ったプログラムをFacadeパターンと呼びます。

以下にFacadeパターンのコード例を示します。

最初にクラスA,クラスB,クラスCを定義します。

C#の例

namespace Facade
{
    public class ClassA
    {
        public void MethodA()
        {
            Console.WriteLine("メソッドAの実行");
        }
    }
}
namespace Facade
{
    public class ClassB
    {
        public void MethodB()
        {
            Console.WriteLine("メソッドBの実行");
        }
    }
}
namespace Facade
{
    public class ClassC
    {
        public void MethodC()
        {
            Console.WriteLine("メソッドCの実行");
        }
    }
}

次に上記3つのクラスをひとまとめにして操作するFacadeクラスを作成します。

namespace Facade
{
    public class Facade
    {
        public void FacadeMethod()
        {
            (new ClassA()).MethodA();
            (new ClassB()).MethodB();
            (new ClassC()).MethodC();
        }
    }
}

最後にFacadeクラスの呼び出し例を以下に示します。

class Program
{
    static void Main(string[] args)
    {
        Facade facade = new Facade();

        facade.FacadeMethod();

        Console.Read();
    }
}

[C#][デザインパターン] Singletonパターン

今回は、デザインパターンの1つであるSingletonパターンを作成してみます。

Singletonパターンは、そのクラスのインスタンスが1つしか生成されないことを保証することができます。

以下はC#におけるSingletonパターンのクラスコードです。

C#の例

public sealed class Singleton
{
    /// <summary>
    /// インスタンスの生成
    /// </summary>
    private static readonly Singleton _singleton = new Singleton();

    /// <summary>
    /// インスタンスを返すプロパティ
    /// </summary>
    public static Singleton Instance
    {
        get {  return _singleton; }
    }

    /// <summary>
    /// コンストラクタ
    /// </summary>
    private Singleton() {

    }
}

コンストラクタの識別子がprivateであることに注目してください。これによりSingletonクラスのインスタンスは外部から作成することができません。

Singletonクラスのインスタンスがほしい場合はInstanceプロパティを参照します。Instanceプロパティは読み取り専用プロパティであり、クラス内部で生成されたインスタンスを返します。

以下にSingletonクラスの使用例を示します。

C#の例

static void Main(string[] args)
{
    Singleton sng1 = Singleton.Instance;
    Singleton sng2 = Singleton.Instance;

    if (sng1 == sng2)
    {
        Console.WriteLine("sng1とsng2は同一のインスタンスです");
    }
}