2014年08月15日

シングルトン

シングルトン

シングルトンとは、あるクラスのインスタンスが一つであるようにする実装パターン。
外部ファイルのような特定のリソースにアクセスする場所を一つにしたい場合や、
固定値のように複数あることに意味がないものを定義する場合などに使用する。

静的クラス

C#(.NET)では、静的クラスという言語仕様レベルでサポートされている機能がある。

    // static指定する。メンバも全員がstatic。
    public static class SingletonSample1
    {
       // constはstaticと違うけど行ける
        public const string Name = "サンプル";

        public static int Number { get { return 0; } }

        public static string DisplayYear(DateTime datetime)
        {
            return datetime.ToString("yyyy年");
        }
    }

実装パターン


シングルトンを実装するばあいは、ほとんど上記の静的クラスで事足りる。 しかし、いくつかの場合においては静的クラスを用いない方法が必要となる場合もある。
 継承を使いたい場合:静的クラスはクラスやインタフェースを継承できない。
 ライフタイムを管理したい場合:静的クラスはメンバのいづれかかが最初に参照またはメソッドコールされた場合にインスタンス化され、プロセス終了まで生存するため任意の契機で生成・消滅させることができない。
 インスタンスを代替したい場合:特定の時機においてインスタンスは最大1だが、なんらかの契機でそれを入れ代える必要がある場合。
 インスタンスが代替可能性があることをコード上で示唆したい場合:機能として静的クラスでもよいのだが、拡張性や可読性を考慮した場合。

    interface ISampleContext
    {
        void DoSomething();
    }

    public class SingletonContext : ISampleContext
    {
        // インスタンス保持領域
        private static SingletonContext _context;

        // 静的コンストラクタ
        static SingletonContext() { _context = new SingletonContext(); }

        // コンストラクタ ※プライベート指定としてクラス外がらのインスタンス化を抑止する
        private SingletonContext(){}

        // 本クラス外からのメンバの使用はこの公開プロパティを介して行う
        public static SingletonContext Instance{get { return _context; }}
 
        public void DoSomething()
        {
            throw new NotImplementedException();
        }
    }
※上記コードの間違いを修正しました。18行目にstaticの指定が抜けてました。(2016/12/23)
posted by RR at 18:26 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年08月16日

ファクトリ・メソッド

Factory method

インスタンスの生成を、news演算子を直接使うのではなくて、Factory(工場)と呼ばれる機能で行う。
Factoryで生成されるインスタンスは、通常は派生クラスとなる。
使用する側は何の派生クラスかを意識せずに、共通の処理をコールすることができる。
インスタンス生成箇所を集約することにより、派生クラスの種類が増えた場合の影響範囲を限定させる。
※インスタンス生成を担う機能(クラス)をFactoryと言う傾向。必ずしも拡張性を考慮したものに限らないみたい。

Sample Code

ファクトリで車(派生としてコンパクトカー・ミドルカー)のインスタンスを生成返却する。
車の種類(下記でコメントアウトされているエコカー)が増えても使用する側(Main)のコードは修正不要。

    class Tester
    {
        static void Main(string[] args)
        {
            // 直接new演算子ではなくFactoryを介してインスタンスを取得
            //var car = new CompactCar();
            var car = Factory.Create(3500000);
            // 車(の種類は意識せず)を運転
            car.Drive();
        }
    }
    // ここでは静的クラスとして実装しているが必須ではない
    static class Factory
    {
       // 引き渡された金額に相当する車の派生クラスのインスタンスを生成・返却
        public static ACar Create(int price)
        {
            if(price <= 1000000)
            {
                throw new ArgumentException();
            }
            else if(price <= 3000000)
            {
                return new CompactCar();
            }
            //else if (price <= 3500000)
            //{
            //    return new EcoCar();
            //}
            else
            {
                return new MiddleCar();
            }
        }
    }

    abstract class ACar
    {
        public abstract void Drive();
    }

    class CompactCar : ACar
    {
        public override void Drive() { }
    }

    class MiddleCar : ACar
    {
        public override void Drive() { }
    }

    //class EcoCar : ACar
    //{
    //    public override void Drive() { }
    //}
posted by RR at 10:56 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年08月17日

アブストラクト・ファクトリー 

AbstactFactory

関連ある複雑なインスタンス群の生成を制約させる場合などに使用。

例えば、ある基本画面に対し付加的な機能を追加できるように実装する場合(アドインを任意に作成できるようにする場合)に、関連するすべてのクラスを生成させるためなどに使う。

Sample Code

ここでは、アドインを作成する側に、メインページクラスとサブページクラスを作成することを制約させてみる。

アドインを使う側でメインページとサブページの継承元クラスを抽象クラスとして定義し、それらを生成するファクトリクラスも抽象クラスとして定義する。
    abstract class AbstractMainPage { }
    abstract class AbstractSubPage { }

    abstract class AbstractFactory
    {
        public abstract AbstractMainPage CreateMainPage();
        public abstract AbstractSubPage CreateSubPage();
    }


アドインを実装する側はこれらを継承してメインページ・サブページ・ファクトリを実装する。
    class SampleMainPage : AbstractMainPage { }
    class SampleSubPage : AbstractSubPage { }
    
    class SampleFactory : AbstractFactory
    {
        public override AbstractMainPage CreateMainPage() { return new SampleMainPage(); }
        public override AbstractSubPage CreateSubPage() { return new SampleSubPage(); }
    }
アドインを使う側で、これらのファクトリを利用して各メインページ・サブページのインスタンスを取得使用する。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace SampleNameSpace
{
    class Tester
    {
        static void Main(string[] args)
        {
            GetFactoryList(args[0]).ToList().ForEach(factory =>
            {
                var mainPage = factory.CreateMainPage();
                var subPage = factory.CreateSubPage();
            });
        }

        // ファクトリの取得
        // ここでは、指定されたアセンブリ名からAbstractFactoryクラスを継承して実装されたクラスを
        // 取得し、そのインスタンスを生成してリストに追加しそのリストを返却している。
        static IList<AbstractFactory> GetFactoryList(string path)
        {
            IList<AbstractFactory> list = new List<AbstractFactory>();
            var typeList = Assembly..Load(path).GetTypes().Where(t => t.BaseType != null && t.BaseType.Name.Equals(typeof(AbstractFactory).Name)).Select(p=>p);

            typeList.ToList().ForEach(t => list.Add(Activator.CreateInstance(t) as AbstractFactory));

            return list;
        }
    }
}

posted by RR at 10:33 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年08月24日

アダプター

Adapter

既存のクラスに変更を加えることなく、本来関連のない型として使用するための方法。
似た実装も含めて使用頻度の高い実装方法。

Sample Code


変更を加えない既存のクラス
    class Adaptee
    {
        public void OldMethod(string message)
        {
            Console.WriteLine(message);
        }
    }

既存クラスと関連がないが、使いたい型(インターフェース)
    interface Target
    {
        void NewMethod(string message);
    }

●継承を使用する方法
    class Adapter1 : Adaptee, Target
    {
        public void NewMethod(string message)
        {
            OldMethod(message);
        }
    }
●委譲を使用する方法
    class Adapter2 : Target
    {
        private Adaptee _adaptee = new Adaptee();

        public void NewMethod(string message)
        {
            _adaptee.OldMethod(message);
        }
    }

使う側
    class Tester
    {
        static void Main(string[] args)
        {
            Target target1 = new Adapter1();
            target1.NewMethod("Test");

            Target target2 = new Adapter2();
            target2.NewMethod("Test");
        }
    }
posted by RR at 21:01 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年09月02日

コンポジット

Composite

直訳すると合成とかいう意味。
ツリー構造のような再帰的なデータ構造を表すために使用する。
TreeViewのようなコントロールにDataBindさせるために使ったりしたけれど、LinqToXMLとかあると使う機会は減るか。
若しくはファイルディレクトリのように異なるものを同一のインタフェースを継承(実現)させることにより統一的に扱えるという実装になる。


Sample Code

    // 枝(Node)と葉(Leaf)とが継承(実現)するインタフェース
    public interface INode
    {
        string Name { get; set; }
        IList<INode> Children { get;}
        void Remove(INode node);
        void Add(INode node);
    }
    // インタフェースを継いた抽象クラス
    public abstract class AbstractNode : INode
    {
        public string Name { get; set;}

        public virtual IList<INode> Children
        {
            get { throw new InvalidOperationException(); }
        }

        public virtual void Remove(INode node)
        {
            throw new InvalidOperationException();
        }

        public virtual void Add(INode node)
        {
            throw new InvalidOperationException();
        }
    }
    // 抽象クラスを継承した葉クラス 
    public class Leaf : AbstractNode
    {

    }
    // 抽象クラスを継承した枝クラス
    // 抽象クラス(インタフェース)を直接継承せず葉クラスを継承する場合もあり
    public class Node : AbstractNode
    {
        private IList<INode> _list;

        public Node()
        {
            _list = new List<INode>();
        }

        public override IList<INode> Children
        {
            get{return _list;}
        }

        public override void Add(INode node)
        {
            _list.Add(node);
        }

        public override void Remove(INode node)
        {
            _list.Remove(node);
        }
    }

posted by RR at 00:33 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年09月04日

デコレーター

Decorator

飾るという意味。
外側にどんどん飾りつけを増やしても、元のAPI(シグネチャ)は変わらない。


Sample Code



    // インタフェースとなる定義
    public abstract class Component
    {
        public abstract void Write();
    }
    // インタフェース(抽象クラス)を継承した具象クラス
    public class ConcreteComponent : Component
    {
        public override void Write()
        {
            Console.WriteLine("Original message");
        }
    }
    // デコレータその1(インタフェースを継承しているところがミソ)
    public class Decorator1 : Component
    {
        public Component Component { get; set; }
        public override void Write()
        {
            Console.WriteLine("--------------");
            Component.Write();
            Console.WriteLine("--------------");
        }
    }
    // こちらもデコレータその2
    public class Decorator2 : Component
    {
        public Component Component { get; set; }
        public override void Write()
        {
            Console.WriteLine("##############");
            Component.Write();
            Console.WriteLine("##############");
        }
    }
これらを使う方のコード
    class Tester
    {
        static void Main(string[] args)
        {
           // オリジナルの出力処理
            Component comp = new ConcreteComponent();
            comp.Write();

            // デコレータで飾った出力
            comp = new Decorator1() { Component = comp };
            comp.Write();

           // デコレートの上塗り
            comp = new Decorator2() { Component = comp };
            comp.Write();
        }
    }

別案

最近は上記のような実装する機会が殆どなくなった。
匿名メソッドとかラムダ式が出てきたから。
インタフェースとか継承元クラスとか定義するのが面倒臭い。
同様のことが簡単に実装できるしね。
こんな感じ

        static void Decoreate(Action action)
        {
            Console.WriteLine("--------------");
            action();
            Console.WriteLine("--------------");
        }

        static void TryCatch(Action action)
        {
            try
            {
                action();
            }
            catch(Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

        public bool AspectLog(Func<bool> func)
        {
            var sw = new Stopwatch();
            sw.Start();
            var ret = func();
            sw.Stop();
            Debug.WriteLine(sw.ElapsedMilliseconds);
            return ret;
        }
posted by RR at 00:00 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年09月07日

ファサード

Facade

語源はフランス語で、玄関という意味。
今でも比較的良く使われるパターンの一つ。
とあるライブラリや機能などに対して、プログラム中の各所から利用する場合に、直接それを使わずにFacadeを介してのみ利用する。
つまり、裏窓とか勝手口とかなどを使わないで出入りはすべて玄関のみとする。
こうすることにより、ライブラリの特殊な使い方を隠蔽したり、ライブラリのAPIが変更されたり、別のライブラリに代替する場合などに影響範囲を限定することが期待できる。

例えば、以下のようなライブラリ(機能)があるとする。
これは、メソッドを特定の順に呼び出す必要があるらしいが、次版リリース時には仕様が変るかもしれない。
namespace Incredible
{
    public class Temporary
    {
        public void DoFirst() { }
        public void DoNext() { }
        public void DoLast() { }
    }
}
上クラスを自身のプロジェクト内のコード各所から参照すると、特定の順序に添ってコールしているかの確認だとか、次版にAPIが変更された場合に、自プロジェクト側の修正箇所が多くなるなどの問題が潜在化している。
このような場合に、これらを隠蔽するためのFacadeクラスを用意する。
    public static class Facade
    {
        public static void DoSomething()
        {
            var temp = new Incredible.Temporary();

            temp.DoFirst();
            temp.DoNext();
            temp.DoLast();
        }
    }
使う側のコード
    class Tester
    {
        static void Main(string[] args)
        {
            Facade.DoSomething();
        }
    }
上例のように、自身側のコードからはFacadeを介してのみ使うことに限定すれば、Temporaryが替わった場合の影響範囲はこのFacadeのみに留まる可能性を期待できる。(必ずそうなるものでもないのは仕方ない)
他のライブラリだけでなく、例えばWin32やWMIに関する機能などを使う場合には、そのまま直接仕様せずに別アセンブリに定義して、それをFacadeを介して使うようにすると、後の変更時に影響範囲を限定させることができるかもしれない。
posted by RR at 01:34 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年09月08日

チェイン・オブ・レスポンシビリティ

Chain of Responsibility

「責任のたらい回し」なんて訳される。
使いどころがないこと無さそうだけれど、使ったこともないし見かけたこともない。


サンプルコード

申請金額が一万円以内なら課長が承認してくれますし、それ以上なら部長に回します。
部長は10万円以内なら承認しますが、それ以上なら社長に回します。
社長は100万円以内なら認めてくれます。
    public interface 社員
    {
        社員 Next(社員 next);

        bool 承認する(int amount);
    }

    public class 社長 : 社員
    {

        public 社員 Next(社員 next)
        {
            throw new InvalidOperationException();
        }

        public bool 承認する(int amount)
        {
            return amount <= 1000000;
        }
    }

    public class 部長 : 社員
    {
        private 社員 _next;

        public 社員 Next(社員 next)
        {
            _next = next;
            return next;
        }

        public bool 承認する(int amount)
        {
            if (amount <= 100000)
            {
                return true;
            }
            else
            {
                return _next.承認する(amount);
            }
        }
    }

    public class 課長 : 社員
    {

        private 社員 _next;

        public 社員 Next(社員 next)
        {
            _next = next;
            return next;
        }

        public bool 承認する(int amount)
        {
            if(amount <=10000)
            {
                return true;
            }
            else
            {
                return _next.承認する(amount);
            }
        }
    }


使う方はこんな感じ

       static void Main(string[] args)
        {
            社員 磯野課長 = new 課長();
            社員 野比部長 = new 部長();
            社員 勇崎社長 = new 社長();

            磯野課長.Next(野比部長).Next(勇崎社長);

            var ret1 = 磯野課長.承認する(5000);
            var ret2 = 磯野課長.承認する(55000);
            var ret3 = 磯野課長.承認する(5555000);
        }
posted by RR at 23:24 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年09月18日

メディエーター

Mediator

「仲介者」と訳される。
「同僚(仲間)」はお互いを直接は知らず、常に仲介者を介する。
あまり出番ないけれど、バシっと決まる場合も偶にある。

サンプルコード

    // 仲介者の抽象親クラス
    abstract class Mediator
    {
        public abstract void SendAll(string message); 
    }
    // 仲介者
    class ConcreatMediator : Mediator
    {
        List<Colleague> _colleagues = new List<Colleague>();

        public void Regist(Colleague colleague){_colleagues.Add(colleague);}


        public override void SendAll(string message)
        {
            _colleagues.ToList().ForEach(_coll => _coll.Notify(message));
        }
    }
    // 同僚の抽象親クラス
    abstract class Colleague
    {
        protected Mediator _mediator;

        public Colleague(Mediator mediator)
        {
            _mediator = mediator;
        }

        public abstract void Send(string message);
        public abstract void Notify(string message);
    }
    // 同僚A
    class ColleagueA : Colleague
    {
        public ColleagueA(Mediator mediator) : base(mediator) { }

        public override void Send(string message){base._mediator.SendAll(message);}

        public override void Notify(string message) { Console.WriteLine("ColleagueA : " + message); }
    }
    // 同僚B
    class ColleagueB : Colleague
    {
        public ColleagueB(Mediator mediator) : base(mediator) { }

        public override void Send(string message) { base._mediator.SendAll(message); }

        public override void Notify(string message) { Console.WriteLine("ColleagueB : " + message); }
    }
    // 同僚C
    class ColleagueC : Colleague
    {
        public ColleagueC(Mediator mediator) : base(mediator) { }

        public override void Send(string message) { base._mediator.SendAll(message); }

        public override void Notify(string message) { Console.WriteLine("ColleagueC : " + message); }
    }



これらを使う側のサンプルコード
    class Tester8
    {
        static void Main(string[] args)
        {
            var mediator = new ConcreatMediator();
            var cA = new ColleagueA(mediator);
            var cB = new ColleagueB(mediator);
            var cC = new ColleagueC(mediator);

            mediator.Regist(cA);
            mediator.Regist(cB);
            mediator.Regist(cC);

            cA.Send("Is anyone there ?");
            cC.Send("Who cares?");
        }
    }


似た感じの実装パターン

クラス間で直接に参照を持ちたくない場合、仲介者のようになんらかを介在させることは割とよく使います。
    public static class Mediator
    {
        public static event Action<string> Notify;
        public static void SendAll(string message)
        {
            if (Notify != null) Notify(message);
        }
    }

    class collA
    {
        public collA()
        {
            Mediator.Notify += message => Console.WriteLine("collA :" + message);
        }

        public void Send(string message) { Mediator.SendAll(message); }
    }
    class collB
    {
        public collB()
        {
            Mediator.Notify += message => Console.WriteLine("collB :" + message);
        }
        public void Send(string message) { Mediator.SendAll(message); }
    }

    class Tester8
    {
        static void Main(string[] args)
        {
            var cA = new collA();
            var cB = new collB();

            cA.Send("Who knows ?");
        }
    }


ここでは仲介者を静的クラスとして定義しましたが、アプリケーションクラスやコンテクストクラスのような場所に実装する場合が多いです。


posted by RR at 00:38 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年09月21日

オブザーバー

Observer

「観察者」とも訳される。
振る舞いに関するパターンが使われる機会が減っていく中で、このオブザーバーパターンは良く見かけます。
DataBindingとかListenerなどもこのパターンの範疇です。

サンプルコード

ここでは、一番基本的な構成のサンプル実装しています。
本店が観察者(Observer)で、支店が観察される方(Observable)です。
支店の従業員が増える毎に本店に連絡が行きます。
なお、以下のサンプルでは実装していませんが、Observableが複数のObserverを持つことに対応するとか、ObserverからObservableへの通知なども可能です。

古典的実装
    // 観察者用インタフェース
    interface IObserver
    {
        void Update(Observable observable);
    }
    // 観察される側の抽象親クラス
    abstract class Observable
    {
        IObserver _observer;

        public void Subscribe(IObserver observer)
        {
            _observer = observer;
        }
        // 観察者に対し変更を通知する
        protected void Update()
        {
            _observer.Update(this);
        }
    }
    // 支店クラス
    class BranchOffice : Observable
    {
    // 支店名
        public string Name { get; set; }
        // 従業員数 この値が更新されると、それを通知する
        private int _count;
        public int MemberCount 
        { 
            get { return _count; }
            set { _count = value; Update(); }
        }
    }
    // 本店(観察者)
    class HeadOffice : IObserver
    {
        private Dictionary<string, int> _dic = new Dictionary<string, int>();

        public void Subscribe(Observable observable)
        {
            observable.Subscribe(this);
        }
        // 観察している対象に変更があると実行される
        public void Update(Observable observable)
        {
            var branch = observable as BranchOffice;

            if(_dic.ContainsKey(branch.Name))
            {
                _dic[branch.Name] = branch.MemberCount;
            }
            else
            {
                _dic.Add(branch.Name, branch.MemberCount);
            }

            DisplayAllMemberCount();
        }

        private void DisplayAllMemberCount()
        {
            Console.WriteLine(_dic.Values.Sum());
        }
    }



それらを使う側のコード
public class Tester
{
        static void Main(string[] args)
        {
            var headOffice = new HeadOffice();
            var shop1 = new BranchOffice() { Name = "shop1" };
            var shop2 = new BranchOffice() { Name = "shop2" };
            var shop3 = new BranchOffice() { Name = "shop3" };

            headOffice.Subscribe(shop1);
            headOffice.Subscribe(shop2);
            headOffice.Subscribe(shop3);

            shop1.MemberCount = 10;
            shop2.MemberCount = 15;
            shop3.MemberCount = 20;
        }
}
同じパターンをEventを使ったサンプル
内容はほぼ一緒ですが、Eventがマルチデリゲートに対応しているので複数の観察者を持つことができます。
Tester側のコードもそのまま使えます。
    public class BranchOffice
    {
        public event Action<BranchOffice> Update;

        public string Name { get; set; }

        private int _count;

        public int MemberCount
        {
            get { return _count; }
            set 
            { 
                _count = value;
                if (Update != null) Update(this); 
            }
        }
    }

    public class HeadOffice
    {
        private Dictionary<string, int> _dic = new Dictionary<string, int>();

        public void Subscribe(BranchOffice observable)
        {
            observable.Update += Update;
        }

        public void Update(BranchOffice observable)
        {
            var branch = observable as BranchOffice;

            if (_dic.ContainsKey(branch.Name))
            {
                _dic[branch.Name] = branch.MemberCount;
            }
            else
            {
                _dic.Add(branch.Name, branch.MemberCount);
            }

            DisplayAllMemberCount();
        }

        private void DisplayAllMemberCount()
        {
            Console.WriteLine(_dic.Values.Sum());
        }
    }
posted by RR at 19:42 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年09月25日

ステート

State

ステートとは状態のこと。
状態を持つクラスを機能毎に定義して、それをコンテクストに保持させる。
使う側は状態を意識せずにコンテクストの同じメソッドを呼ぶ。
実装コストの割に合わないケースが多いのか、あまり使われていない気がする。

サンプルコード

基本構成例。
Stateを継承したクラスが2種ある。使う側はコンテクストのメソッドのみを使用する。
   // 状態クラス用のインタフェース定義
    public interface State
    {
         void Do(Context context);
    }
    // 状態Aクラス
    public class StateA : State
    {
        public void Do(Context context)
        {
            Console.WriteLine("Do something in StateA");
            context.State = new StateB();
        }
    }
    // 状態Bクラス
    public class StateB : State
    {
        public void Do(Context context)
        {
            Console.WriteLine("Do something in StateB");
            context.State = new StateA();
        }
    }
    // コンテクストクラス
    public class Context
    {
        public State State { get; set; }

        public void Execute()
        {
            State.Do(this);
        }
    }


これを使う側のコード例
    class Tester
    {
        static void Main(string[] args)
        {
            var context = new Context() { State = new StateA() };

            context.Execute(); // StateA.Do()
            context.Execute(); // StateB.Do()
            context.Execute(); // StateA.Do()
         }
     }


サンプルその2

教室事例的ですが、ちょっと具体的な例。
状態として金額を持ちます。
閾値以下なら貧乏状態、以上なら金持ち状態です。
金持ちなら3000円ランチ、貧乏なら500円ランチを食べます。
500円もないと何も食べられません。

    // 状態
    abstract class State
    {
        // 金持ちと貧乏との閾値
        protected const int threshold = 10000;
        // 所持金  値変更時(Setter)に状態チェックを実行します
        private int _amount;
        public int Amount { get { return _amount; } set { _amount = value; Check(); } }
        // コンテキスト
        public Context Context { get; set; }
        // 食事する
        public abstract void Lanch();
        protected abstract void Check();
    }
    // 貧乏状態
    class PoorState : State
    {
        public PoorState(Context context)
        {
            Context = context;
        }
        public PoorState(State state)
        {
            Context = state.Context;
            Amount = state.Amount;
        }
        public override void Lanch()
        {
            if(Amount < 500)
            {
                Console.WriteLine("昼食なし");
            }
            else
            {
                Console.WriteLine("500円ランチ");
                Amount = Amount - 500;
            }
        }
        protected override void Check()
        {
            if (Amount >= threshold)
            {
                Context.State = new RichState(this);
            }
        }
    }
   // 金持ち状態
    class RichState : State
    {
        public RichState(Context context)
        {
            Context = context;
        }
        public RichState(State state)
        {
            Context = state.Context;
            Amount = state.Amount;
        }
        public override void Lanch()
        {
            Console.WriteLine("3000円ランチ");
            Amount = Amount - 3000;   
        }
        protected override void Check()
        {
            if (Amount < threshold)
            {
                Context.State = new PoorState(this);
            }
        }
    }
    // コンテキスト
    class Context
    {
        public State State { get; set; }

        public Context()
        {
            State = new PoorState(this);
        }

        public void AddAllowance(int amount)
        {
            State.Amount += amount;

            Console.WriteLine("{0}円追加。残金{1}円",amount, State.Amount);
        }

        public void EatLanch()
        {
            State.Lanch();

            Console.WriteLine("残金{0}円", State.Amount);
        }
    }

これを使う側のコード
    class Tester
    {
        static void Main(string[] args)
        {
           var context = new Context();
            context.EatLanch();           // 昼飯なし    残金0円
            context.AddAllowance(3000);   // 3000円追加  残金3000円
            context.EatLanch();           // 500円ランチ 残金2500円
            context.AddAllowance(8000);   // 8000円追加  残金10500円
            context.EatLanch();           // 3000円ランチ 残金7500円 
            context.EatLanch();           // 500円ランチ 残金7000円
        }
    }

posted by RR at 00:30 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

ストラテジー

Strategy

戦略という意味。
比較的良く目にするパターンであり、使いどころも結構あります。
アルゴリズム(戦略)自体を使用する側のIFを変えることなく代替可能にする。

サンプルコード

基本構成
    interface IStrategy
    {
        void DoSomething();
    }

    class StrategyA : IStrategy
    {
        public void DoSomething()
        {
            Console.WriteLine("Strategy A.");
        }
    }

    class StrategyB : IStrategy
    {
        public void DoSomething()
        {
            Console.WriteLine("Strategy B.");
        }
    }

    class Context
    {
        public IStrategy Strategy { set; private get; }
         
        public void Execute()
        {
            Strategy.DoSomething();
        }
    }

    class Tester
    {
        static void Main(string[] args)
        {
            var ctxt = new Context();
            ctxt.Strategy = new StrategyA();
            ctxt.Execute();
            ctxt.Strategy = new StrategyB();
            ctxt.Execute();
        }
    }

サンプルコード

もう少し具体的な使用例

    // 基本は「戦え」
    interface IStrategy
    {
        void Fight();
    }
    // 抽象基底クラスの定義 メンバが3人居ます。
    abstract class AStrategy : IStrategy
    {
        protected Member Soldire;
        protected Member Priest;
        protected Member Magician;

        public AStrategy()
        {
            Soldire = new Member() { Job = "戦士" };
            Priest = new Member() { Job = "僧侶" };
            Magician = new Member() { Job = "魔法使い" };
        }

        public abstract void Fight();
        
    }
    // 強気の戦略
    class BullStrategy : AStrategy
    {
        public override void Fight()
        {
            Console.WriteLine("ガンガンいこうぜ");
            Soldire.SetCommand("攻撃");
            Priest.SetCommand("ザキ");
            Magician.SetCommand("イオナズン");
        }
    }
    // 通常時の戦略
    class NormalStrategy : AStrategy
    {
        public override void Fight()
        {
            Console.WriteLine("みんながんばれ");
            Soldire.SetCommand("攻撃");
            Priest.SetCommand("ホイミ");
            Magician.SetCommand("メラミ");
        }
    }
    // 弱気の戦略
    class BearStrategy : AStrategy
    {
        public override void Fight()
        {
            Console.WriteLine("いのちだいじに");
            Soldire.SetCommand("薬草");
            Priest.SetCommand("べホイミ");
            Magician.SetCommand("防御");
        }
    }
    // 戦略をラップ(カプセル化)します。
    class Context
    {
        public IStrategy Strategy { set; private get; }

        public void Execute()
        {
            Strategy.Fight();
        }
    }
    // メンバークラス 職業名とコマンド
    public class Member
    {
        public string Job{get;set;}
        public void SetCommand(string command)
        {
            Console.WriteLine("{0} {1}", Job, command);
        }
    }


これらを使う方のコード
    class Tester
    {
       static void Main(string[] args)
        {
            var ctxt = new Context();
            ctxt.Strategy = new BullStrategy();
            ctxt.Execute();
            ctxt.Strategy = new NormalStrategy();
            ctxt.Execute();
            ctxt.Strategy = new BearStrategy();
            ctxt.Execute();
        }
    }

posted by RR at 23:22 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年09月27日

テンプレート

Template

テンプレートとは「型枠」とか「鋳型」という意味であった。
デザインパターンでは、処理の大枠を基底クラス側で、具体的な内容はサブクラス側で定義する。

サンプルコード

基本構成は以下のようなもの。
    // 基底となる抽象クラス
    public abstract class TemplateBase
    {
        // このメソッドが呼ばれる
        public void TemplateMethod()
        {
            Method1();
            Method2();
            Method3();
        }
        // 個々の実装はサブクラス側に任せる
        public abstract void Method1();
        public abstract void Method2();
        public abstract void Method3();
    }
    // サブクラスA
    public class TemplateA : TemplateBase
    {
        public override void Method1()
        {
            Console.WriteLine(" TemplateA Method1");
        }
        public override void Method2()
        {
            Console.WriteLine(" TemplateA Method2");
        }
        public override void Method3()
        {
            Console.WriteLine(" TemplateA Method3");
        }
    }
    // サブクラスB
    public class TemplateB : TemplateBase
    {
        public override void Method1()
        {
            Console.WriteLine(" TemplateB Method1");
        }
        public override void Method2()
        {
            Console.WriteLine(" TemplateB Method2");
        }
        public override void Method3()
        {
            Console.WriteLine(" TemplateB Method3");
        }
    }

    // これらを使う側
    class Tester
    {
        static void Main(string[] args)
        {
            TemplateBase ta = new TemplateA();
            ta.TemplateMethod();

            TemplateBase tb = new TemplateB();
            tb.TemplateMethod();
         }
     }


サンプル

具体的な使用例
ここでは処理を想定の順序で使われることを強制している。
    public abstract class DatabaseAccessBase
    {
       // このメソッドが呼ばれることにより、必ず
       // Open→Execute→Closeの順が保障される。
        public ArrayList Select(string command)
        {
            Open();
            var ret = ExecuteQuery(command);
            Close();

            return ret;
        }

        public abstract void Open();
        public abstract ArrayList ExecuteQuery(string command);
        public abstract void Close();
    }

    public class SqlServerAccess : DatabaseAccessBase
    {
        private IDbConnection _cnn;
        public override void Open()
        {
            _cnn = new SqlConnection(@"connectionString");
            _cnn.Open();
        }
        public override ArrayList ExecuteQuery(string command)
        {
            var cmd = _cnn.CreateCommand();
            cmd.CommandText = command;

            var reader = cmd.ExecuteReader();
            var list = new ArrayList();

            while(reader.Read())
            {
                object[] values = new object[reader.FieldCount];
                list.Add(reader.GetValues(values));
            }

            return list;
        }

        public override void Close()
        {
            _cnn.Close();
            _cnn.Dispose();
        }
    }

サンプルその3

処理の大枠は基底クラス側で実装し、内容の異なる部分のみサブクラス側で実装するパターン。
    public abstract class ExerciseBase
    {
        public void TakeExercise()
        {
            WarmingUP();
            Do();
            CoolDown();
        }

        virtual protected void WarmingUP()
        {
            Console.WriteLine("Warming up..");
        }
        abstract protected void Do();
        virtual protected void CoolDown()
        {
            Console.WriteLine("Cool down..");
        }
    }

    public class Running : ExerciseBase 
    {
        protected override void Do()
        {
            Console.WriteLine("Running...");
        }
    }

    public class Jogging : ExerciseBase
    {
        protected override void WarmingUP()
        {
            Console.WriteLine("Nothing to do..");
        }
        protected override void Do()
        {
            Console.WriteLine("Jogging...");
        }
    }

    class Tester
    {
        static void Main(string[] args)
        {
            var run = new Running();
            run.TakeExercise();

            var jog = new Jogging();
            jog.TakeExercise();
        }
    }

posted by RR at 23:41 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年09月28日

ビジター

Visitor

訪問者のこと。
廃れることは無いとは思いますが、最近はあまり使われてないかも。

サンプルコード

Visitor Patternを使用しない例
    // 貯金箱
    class Moneybox
    {
        public int Amount { get; set; }
    }
    // 借金
    class Debt
    {
        public int Owed { get; set; }
    }
    // 財政状況
    class Finance 
    {
        List<Moneybox> _moneys = new List<Moneybox>();
        public List<Moneybox> MoneyBoxs { get { return _moneys ; } }

        List<Debt> _debts = new List<Debt>();
        public List<Debt> DebtList{ get { return _debts ; } }
    }

    class Tester
    {
        static void Main(string[] args)
        {
             Finance finance = new Finance();
             finance.MoneyBoxs.Add(new Moneybox{Amount = 5000});
             finance.MoneyBoxs.Add(new Moneybox{Amount = 3000});
             finance.DebtList.Add(new Owed{owed=2000});
 
             int sum;
             finance.MoneyBoxs.ForEach(mb ==> sum += mb.Amount);
             finance.DebtList.ForEach(debt==> sum -= debt.Owed);
         }
    }

上記をVisitor Patternを適用して書きお直します。
    // 訪問者
    interface IVisitor
    {
        void Visit(IVisitable visitable);
    }
    // 訪問される側
    interface IVisitable
    {
        void Accespt(IVisitor visitor);
    }

    class Moneybox : IVisitable
    {
        public int Amount { get; set; }

        public void Accespt(IVistor visitor)
        {
            visitor.Visit(this);
        }
    }
    class Debt : IVisitable 
    {
        public int Owed { get; set; }

        public void Accespt(IVistor visitor)
        {
            visitor.Visit(this);
        }
    }

    class Finance : IVisitable 
    {
        List<IVisitable> _assets = new List<IVisitable>();
        public List<IVisitable> Assets { get { return _assets; } }

        public void Accespt(IVisitor visitor)
        {
            _assets.ForEach(asset => asset.Accespt(visitor));
        }
    }
    class Visitor : IVisitor
    {
        public int Sum { get; set; }

        public void Visit(IVisitable visitable)
        {
            if(visitable is Moneybox)
            {
                Sum += ((Moneybox)visitable).Amount;
            }
            else if(visitable is Debt)
            {
                Sum -= ((Debt)visitable).Owed;
            }
        }
    }

    // 使用する側
    class Tester
    {
        static void Main(string[] args)
        {
            Finance finance = new Finance();
            finance.Assets.Add(new Moneybox { Amount = 5000 });
            finance.Assets.Add(new Moneybox { Amount = 3000 });
            finance.Assets.Add(new Debt { Owed = 2000 });

            // ここで計算していた分をVisitor側で行うよう修正
            Visitor visitor = new Visitor();
            finance.Accespt(visitor);

            int sum = visitor.Sum;
         }
    }

posted by RR at 10:32 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする

2014年10月24日

デザインパターンとは

GoFによる「Design patterns elements of reusable object-oriented software」が出版されたのが1994年。


その邦訳「オブジェクト指向における再利用のためのデザインパターン」が刊行されたのがその翌年。


C言語にクラスの概念を追加したと言われるC++が出て約10年で、Javaの最初の版が出た頃でしょうか。C#が出るのはそれから四年後ぐらい。

今の時点で振り返ってみると、どうして取り上げられたのか良く解らないものや、同じような構成を視点を変えてみているようなものがあったり、他にもっと取り上げられるべきものがあるようにも思えます。

また、言語仕様や開発環境などの変化により使われなくなって久しいものもかなりあるようです。

C#言語に限って言えば、最早オブジェクト指向言語とは言い切れないですし、そのまま取り入れるには、そのコストに見合う分だけのメリットがあるのか要考慮が必要なものも多いように思われます。

また、拡張性を見越した設計でも、それが役に立つなんてことは経験則上あまりないですし、保守性を勘案するなら沢山のクラスやメンバなどを記述するよりはIF文などが含まれていようが、なるべく短いコードにしてもらうとか、命名規約やコーディング規約に沿って書いてもらうほうが遥かに良いことが多い気もします。

それでも、自分で読み書きする機会は減りましたが、知らなくていいとまでは言い切れない状況でしょう。技術者間ではこういう概念を知っているのが前提として会話が進むこともまだまだありますし、オープンソースなどでは直接間接にデザインパターンのようなものを未だに良く見かけます。

posted by RR at 00:23 | Comment(0) | デザインパターン | このブログの読者になる | 更新情報をチェックする