×

[PR]この広告は3ヶ月以上更新がないため表示されています。
ホームページを更新後24時間以内に表示されなくなります。

C#デザインパターン  - Observer

ここに掲載したコードは、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』に掲載されているサンプルコードをC#に移植したものです。
解説らしい解説は載せていませんので、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』も合わせてお読みください。

※当ソースは、Visual C# 2008 Express Editionで動作を確認しています。
  Visual Studio 2005をお使いの方は、ブログの記事を残しておきますので、そちらをご覧ください。



■NumberGenerator.cs
using System;

namespace Gushwell.DesignPatterns {

    public abstract class NumberGenerator {
        public event EventHandler<NumberGeneratorEventArgs> Stepped;

        // イベントを発行する。通知する相手が誰かは把握していない。
        // これだけで、登録されている複数のイベントハンドラを呼び出せる。
        protected void OnStepped(int number) {
            if (Stepped != null) {
                NumberGeneratorEventArgs args = new NumberGeneratorEventArgs(number);
                Stepped(this, args);
            }
        }

        // 数を生成する
        public abstract void Execute();
    }
}


■NumberGeneratorEventArgs.cs
using System;

namespace Gushwell.DesignPatterns {
    public class NumberGeneratorEventArgs : EventArgs {
        public NumberGeneratorEventArgs(int num) {
            Number = num;
        }
        public int Number { get; set; }
    }
}


RandomNumberGenerator.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Gushwell.Dejavu;

namespace Gushwell.DesignPatterns {
    public class RandomNumberGenerator : NumberGenerator {

        public override void Execute() {
            RandomMaker.Random(51).Take(20)
                .ForEach(n => OnStepped(n));
        }
    }

    // LINQ の機能を使ってみました。
    public static class RandomMaker {
        // 0 - maxValue-1 の間で乱数を無限に発生させる。
        public static IEnumerable<int> Random(int maxValue) {
            Random random = new Random();
            while (true) {
                yield return random.Next(maxValue);
            }
        }
    }
}

■DigitObserver.cs
using System;
using System.Threading;

namespace Gushwell.DesignPatterns {

    public class DigitObserver  {
        public void Update(object sender, NumberGeneratorEventArgs args) {
            Console.WriteLine("DigitObserver:" + args.Number);
            Thread.Sleep( 100 );
        }
    }
}


GraphObserver.cs
using System;
using System.Threading;

namespace Gushwell.DesignPatterns {

    public class GraphObserver  {
        public void Update(object sender, NumberGeneratorEventArgs args) {
            Console.Write("GraphObserver:");
            Console.Write(new string('*', args.Number));
            Console.WriteLine("");
            Thread.Sleep(100);
        }
    }
}



Program.cs
using System;
using System.Threading;

namespace Gushwell.DesignPatterns {

    public class Program {
        [STAThread]
        public static void Main(string[] args) {
            NumberGenerator generator = new RandomNumberGenerator();

            // 書き方2 
            // 書籍『デザインパターン入門』に忠実に、クラスのメソッドに変更を通知
            var observer1 = new DigitObserver();
            var observer2 = new GraphObserver();
            generator.Stepped += observer1.Update;
            generator.Stepped += observer2.Update;
            generator.Execute();

            // 書き方2 
            // こんな書き方もできる。Observerクラスは不要。
            // イベントだから、イベントハンドラを別クラスに定義する必要はない。
            // どちらが良いかは、なんとも言い難い。役割分担をどうするかの判断によると思う。
            NumberGenerator generator2 = new RandomNumberGenerator();
            generator2.Stepped += DigitUpdate;
            generator2.Stepped += GraphUpdate;
            generator2.Execute();
        }

        // 書き方2で必要
        static void DigitUpdate(object sender, NumberGeneratorEventArgs e) {
            Console.WriteLine("DigitObserver:" + e.Number);
            Thread.Sleep(100);
        }

        // 書き方2で必要
        static void GraphUpdate(object sender, NumberGeneratorEventArgs e) {
            Console.Write("GraphObserver:");
            Console.Write(new string('*', e.Number));
            Console.WriteLine("");
            Thread.Sleep(100);
        }
    }
}




■EnumerableExtentions.cs
using System;
using System.Collections.Generic;

namespace Gushwell.Dejavu {
    public static class EnumerableExtentions {
        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
            foreach (var x in source) {
                action(x);
            }
        }
    }
}