C#

【C#】Observer Pattern(オブザーバパターン)で書くサンプルプログラム

アイキャッチ(c_sharp)

こんにちは!
なかむぅです。

ずっとコピペプログラマーだった私は

オブジェクト指向?なにそれ美味しいの?

って感じだったので、「オブジェクト指向」を学ぶために「Java言語で学ぶデザインパターン入門第3版」を購入しました。

そのデザインパターンの一つ「Observer Pattern(オブザーバパターン)」をC#で書いていこうと思います。


我が社で一緒に働きませんか?

私が働く会社では、一緒に働いてくれるエンジニアを募集しています♪

我が社のココがアツイ!!
  • 未経験、第二新卒歓迎
  • 学歴・転職回数・離職期間不問
  • 残業は月15時間以下で残業代は全額支給
  • 経験者は月給23万円以上
  • 年収100万以上UP↑↑↑も可能
  • 長く働いていても年収が全然上がらないから、一気に年収を上げたい
  • 残業をしたくてしているわけではないので、残業代はしっかりと出して欲しい
  • やりたいことに挑戦させてもらえないから、自分がしてみたいことに挑戦したい
  • 通勤時間が長すぎるから、できるだけ短くしたい
  • もっと勉強したいから、書籍代など負担してくれるところに入りたい
  • 現場に駆り出されてからは放置プレイで、相談できる人も先輩も居ないので、自分の状況をちゃんと理解してくれるところで働きたい

上記内容に1つでも当てはまる場合は、ぜひご検討ください。

詳細ページ


Observer Pattern(オブザーバパターン)

身近なもので言うとLINEのグループようなものです。

LINEのグループ?なんだそれ

という方は、まず友達作りから始めてください。

ある人がLINEを送る(変更する)と、グループに所属している人たちにメッセージが送られて通知(変更を通知する)が来ます。
(どっちかというと公式LINEからの通知に近いかもしれない)

このように変更がされたことを然るべきところに通知するのがObserver Pattern(オブザーバパターン)です。

生成された数値を数字とグラフで通知するプログラム

ランダムな数を生成するクラスと偶数を生成するクラスがあり、それぞれの数値を数字とグラフで通知するObserverが存在しているプログラムです。

Observerを疎結合にするためにIObserverインタフェースを使ってObserverを実装します。

IObserver Observer用のインタフェース
NumberGenerator 数を生成する抽象クラス
RandomNumberGenerator ランダムな数を生成するクラス
EvenNumberGenerator 偶数を生成するクラス
DigitObserver 生成された数値をそのまま通知するクラス
GraphObserver 生成されてた数値をアスタリスクのグラフで通知するクラス

IObserverインタフェース

IObserver.cs

//Observer用のインタフェースを作って疎結合できるようにしておく
public interface IObserver
{
	public void Update(NumberGenerator generator);
}

NumberGeneratorクラス

NumberGenerator.cs

//数を生成する抽象クラス
public abstract class NumberGenerator
{
	//通知するObserverを保持するList
	private List<IObserver> _observers = new List<IObserver>();
	//ObserverをListに追加する
	public void AddObserver(IObserver observer)
	{
		_observers.Add(observer);
	}

	//Listに保持されたObserverへ通知する
	public void NotifyObservers()
	{
		foreach (IObserver o in _observers)
		{
			//Listに保持されている各ObserverのUpdateメソッドが呼ばれる
			o.Update(this);
		}
	}

	//数を取得するための抽象プロパティ
	public abstract int Number { get; }
	//実行するための抽象メソッド
	public abstract void Execute();
}

RandomNumberGeneratorクラス

RandomNumberGenerator.cs

//ランダムな数を生成するクラス
public class RandomNumberGenerator : NumberGenerator
{
	//生成した数を保持するフィールド
	private int _number;
	public override int Number => _number;

	private Random _random = new Random();
	//数を生成して通知する
	public override void Execute()
	{
		for (int i = 0; i < 20; i++)
		{
			_number = _random.Next(50);
			NotifyObservers();
		}
	}
}

EvenNumberGeneratorクラス

EvenNumberGenerator.cs

//偶数を生成するクラス
public class EvenNumberGenerator : NumberGenerator
{
	//生成した数を保持するフィールド
	private int _number;
	public override int Number => _number;

	private Random _random = new Random();
	//数を生成して通知する
	public override void Execute()
	{
		for (int i = 0; i < 20; i++)
		{
			_number = _random.Next(50);
			//奇数だったら1を足して偶数にする
			if (_number % 2 == 1)
			{
				_number++;
			}
			NotifyObservers();
		}
	}
}

DigitObserverクラス

DigitObserver.cs

//生成された数値をそのまま通知するクラス
public class DigitObserver : IObserver
{
	private Random _random = new Random();
	public void Update(NumberGenerator generator)
	{
		Console.WriteLine("DigitObserver:" + generator.Number);
		try
		{
			//通知されていることをわかりやすくするために遅らせる
			Thread.Sleep(_random.Next(100, 1000));
		}
		catch (Exception e)
		{
		}
	}
}

GraphObserverクラス

GraphObserver.cs

//生成されてた数値をアスタリスクのグラフで通知するクラス
public class GraphObserver : IObserver
{
	private Random _random = new Random();
	public void Update(NumberGenerator generator)
	{
		//生成された数値分のアスタリスクを並べる
		var asterisk = "";
		for (int i = 0; i < generator.Number; i++)
		{
			asterisk += "*";
		}
		Console.WriteLine($"GraphObserver:{asterisk}");
		try
		{
			//通知されていることをわかりやすくするために遅らせる
			Thread.Sleep(_random.Next(100, 1000));
		}
		catch (Exception e)
		{
		}
	}
}

使い方

Program.cs

class Program
{
	static void Main(string[] args)
	{
		//Observerのインスタンスを生成
		var observer1 = new DigitObserver();
		var observer2 = new GraphObserver();
		Console.WriteLine("ランダムな数を生成して通知する");
		var randomNumberGenerator = new RandomNumberGenerator();
		randomNumberGenerator.AddObserver(observer1);
		randomNumberGenerator.AddObserver(observer2);
		randomNumberGenerator.Execute();
		Console.WriteLine();
		Console.WriteLine("偶数を生成して通知する");
		var evenNumberGenerator = new EvenNumberGenerator();
		evenNumberGenerator.AddObserver(observer1);
		evenNumberGenerator.AddObserver(observer2);
		evenNumberGenerator.Execute();
	}
}
結果

ランダムな数を生成して通知する
DigitObserver:47
GraphObserver:***********************************************
DigitObserver:2
GraphObserver:**
DigitObserver:26
GraphObserver:**************************
DigitObserver:42
GraphObserver:******************************************
DigitObserver:3
GraphObserver:***
DigitObserver:6
GraphObserver:******
DigitObserver:5
GraphObserver:*****
DigitObserver:32
GraphObserver:********************************
DigitObserver:40
GraphObserver:****************************************
DigitObserver:31
GraphObserver:*******************************
DigitObserver:17
GraphObserver:*****************
DigitObserver:49
GraphObserver:*************************************************
DigitObserver:19
GraphObserver:*******************
DigitObserver:40
GraphObserver:****************************************
DigitObserver:40
GraphObserver:****************************************
DigitObserver:15
GraphObserver:***************
DigitObserver:47
GraphObserver:***********************************************
DigitObserver:18
GraphObserver:******************
DigitObserver:1
GraphObserver:*
DigitObserver:17
GraphObserver:*****************

偶数を生成して通知する
DigitObserver:30
GraphObserver:******************************
DigitObserver:28
GraphObserver:****************************
DigitObserver:16
GraphObserver:****************
DigitObserver:18
GraphObserver:******************
DigitObserver:26
GraphObserver:**************************
DigitObserver:14
GraphObserver:**************
DigitObserver:8
GraphObserver:********
DigitObserver:44
GraphObserver:********************************************
DigitObserver:14
GraphObserver:**************
DigitObserver:18
GraphObserver:******************
DigitObserver:10
GraphObserver:**********
DigitObserver:16
GraphObserver:****************
DigitObserver:22
GraphObserver:**********************
DigitObserver:40
GraphObserver:****************************************
DigitObserver:0
GraphObserver:
DigitObserver:48
GraphObserver:************************************************
DigitObserver:28
GraphObserver:****************************
DigitObserver:50
GraphObserver:**************************************************
DigitObserver:2
GraphObserver:**
DigitObserver:16
GraphObserver:****************

まとめ

今回はコンソールアプリで実装しましたが、グラフと表が連動したWebアプリやWPFで作った画面が連動するWindowsアプリなどで実装すると面白そうですね。

暇な時に作ってみようと思います。

いやここは違うだろ

と思った方はコメントいただけると嬉しいです。

最後までお読みいただきありがとうございました!


我が社で一緒に働きませんか?

私が働く会社では、一緒に働いてくれるエンジニアを募集しています♪

我が社のココがアツイ!!
  • 未経験、第二新卒歓迎
  • 学歴・転職回数・離職期間不問
  • 残業は月15時間以下で残業代は全額支給
  • 経験者は月給23万円以上
  • 年収100万以上UP↑↑↑も可能
  • 長く働いていても年収が全然上がらないから、一気に年収を上げたい
  • 残業をしたくてしているわけではないので、残業代はしっかりと出して欲しい
  • やりたいことに挑戦させてもらえないから、自分がしてみたいことに挑戦したい
  • 通勤時間が長すぎるから、できるだけ短くしたい
  • もっと勉強したいから、書籍代など負担してくれるところに入りたい
  • 現場に駆り出されてからは放置プレイで、相談できる人も先輩も居ないので、自分の状況をちゃんと理解してくれるところで働きたい

上記内容に1つでも当てはまる場合は、ぜひご検討ください。

詳細ページ


COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です