Duplicate Observed Data(観察されるデータの複製)


HOME > プログラミング > リファクタリング > Duplicate Observed Data リファクタリング プログラムの体質改善テクニック

Duplicate Observed Dataとは、UIのクラス内で使用されるデータを切り出し、
UIとそのデータとのやりとりをObserverパターンを用いて行うようにリファクタリングすることです。

ユーザーインターフェイスのクラスの中にだけ存在するようなデータは、クラスとして切り出すところに第一歩があります。
ユーザーインターフェイスのクラスはユーザーインターフェイスの制御にだけ集中すべきで、データの保持は別のクラスとするべきだからです。
このリファクタリングの第一歩はExtract Class(クラスの抽出)でデータクラスをUIクラスから独立させることになります。

このリファクタリングのもう一つのエッセンスがobserverパターンを導入することです。
observerパターンは、主に1つの入力に対して2つ以上の表示項目が関係している場合に利用するとコードがすっきりします。
たとえば、2つの入力フィールドが相互に関係している場合(文字と文字数など)、
同じデータを元にした2つの表示が存在(数字とグラフで表示など)するようなアプリケーションなどでobserverを検討する価値があると言えます。
もちろんデータが変化したことを単純に通知しなければならないようなコードでも有効です。

observerパターンが本当に必要になるまでは、observerパターンは実装しない方が良い(パターン指向リファクタリング)という意見がありますので、
あまり意味のないobserverの乱用に注意しましょう。

リファクタリング前:

using System;

namespace Observer
{
	//メインクラスです
	public class Observer
	{
		public static void Main()
		{
			GUI gui = new GUI();

			for(int i=0; i < 10; i++)
			{
				if(i != 0)
				{
					gui.Name +=  ",";
				}

				gui.Name += i.ToString();
				gui.Display();
			}

		}

	}

	public class GUI
	{
		private string name = "";

		public string Name
		{
			get
			{
				return this.name;
			}
			set
			{
				this.name = value;
			}
		}

		public void Display()
		{
			Console.WriteLine(name);
		}
	}
}

	  

リファクタリング後:

using System;

namespace Observer
{
	//メインクラスです
	public class Observer
	{
		public static void Main()
		{
			GUI gui = new GUI();
			Data data = new Data();

			//通知を受ける関数の登録
			ChangedEventHandler eventHandler = new ChangedEventHandler(gui.update);

			data.Changed += eventHandler;

			//DataのNameを変更してみる
			for(int i=0; i < 10; i++)
			{
				if(i != 0)
				{
					data.Name +=  ",";
				}

				data.Name += i.ToString();
			}

			data.Changed -= eventHandler;
		}

	}

	//イベントに対してdelegateを宣言するt
	public delegate void ChangedEventHandler(object sender);

	//observable class
	//変更されたときに通知します
	public class Data
	{
		//declare the event using the delegate
		public event ChangedEventHandler Changed;

		private string name = "";
       
		public string Name
		{
			get
			{
				return name;
			}
			set
			{
				this.name = value;

				//データが変更されたときに通知することをここで集中管理
				OnChange(this);
			}
		}

		private void OnChange(object sender)
		{
			if(Changed != null)
			{	
				Changed(sender);
			}
		}
	}

	//observer class
	//変更の通知を受けます
	public class GUI
	{
		public void update(object sender)
		{
			Console.WriteLine(((Data)sender).Name);
		}
	}
}



Copyright(c) 2012 WoodenSoldier Software