Decoupling Design

C#で示しますが、他のオブジェクト指向言語なら、考え方は一緒。

改善対象

//Strategy パターン

public interface IOrderStrategy

{

void Insert(OrderInfo order);

}

public class OrderSynchronous : IOrderStrategy

{

public void Insert(OrderInfo order)

{

//implementation

}

}

public class OrderAsynchronous : IOrderStrategy

{

public void Insert(OrderInfo order)

{

//implementation

}

}

改善方法

1.設定ファイル

2.Table-Driven Approach

3.DI

4.CoC

1.設定ファイル

(1)シンプル式

public static class BLLFactory

{

public static IOrderStrategy CreateStrategy()

{

string path = ConfigurationManager.AppSettings["StrategyPath"];

string className = ConfigurationManager.AppSettings["StrategyClass"];

return Assembly.Load(path).CreateInstance(className) as IOrderStrategy;

}

}

呼び出す先

IOrderStrategy strategy = BLLFactory.CreateStrategy();

Order order = new Order(strategy);

order.Insert( new OrderInfo() );

設定ファイル

<add key="StrategyPath" value="NET.BLL"/>

<add key="StrategyClass" value="BLL.OrderSynchronous" />

2.Table-Driven Approach

public static class OrderManager

{

private static IDictionary<string, IOrderStrategy> strategyTable;

static OrderManager()

{

strategyTable = new Dictionary<string, IOrderStrategy>

{

{"sync", new OrderSynchronous()},

{"async", new OrderAsynchronous()}

};

}

public static IOrderStrategy GetStrategy(string key)

{

IOrderStrategy strategy;

if (strategyTable.TryGetValue(key, out strategy))

{

return strategy;

}

else

{

throw new Exception("Not Found Strategy");

}

}

public static void RegisterStrategy(string key, IOrderStrategy strategy)

{

if(string.IsNullOrEmpty(key))

{

throw new ArgumentNullException(key);

}

if (strategy == null)

{

throw new ArgumentNullException("IS NULL");

}

if (strategyTable.ContainsKey(key))

{

throw new ArgumentException("Key existed");

}

strategyTable.Add(key, strategy);

}

}

呼び出す先

string strategyKey = ConfigurationManager.AppSettings["StrategyKey"];

IOrderStrategy strategy = OrderManager.GetStrategy(strategyKey);

Order order = new Order(strategy);

order.Insert( new OrderInfo() );

設定ファイル

<add key="StrategyKey" value="sync"/>

public class Order

{

private IOrderStrategy strategy;

public Order(IOrderStrategy strategy)

{

this.strategy = strategy;

}

public void Insert(OrderInfo order)

{

this.strategy.Insert(order);

}

}

呼び出す先

Order order = new Order( new OrderAsynchronous() );

order.Insert( new OrderInfo() );

※依頼が発生してしまった!

(2)Generics式

public static class BLLFactory<T> where T : class

{

public static T Create(string key)

{

return FactoryHelper<T>.Create(

key,

ConfigurationManager.AppSettings["BLLAssembly"],

ConfigurationManager.AppSettings["BLLPath"]);

}

}

public static class FactoryHelper<T> where T : class

{

private static T instance;

public static T Create(string key, string nameSpace, string path)

{

if (instance == null)

{

string className =

nameSpace + "." + ConfigurationManager.AppSettings[key];

instance = Assembly.Load(path).CreateInstance(className) as T;

}

return instance;

}

}

呼び出す先

IOrderStrategy strategy = BLLFactory<IOrderStrategy>.Create("IOrderStrategy");

Order order = new Order(strategy);

order.Insert( new OrderInfo() );

設定ファイル

<add key="BLLAssembly" value="BLL"/>

<add key="BLLPath" value="NET.BLL"/>

<add key="IOrderStrategy" value="OrderSynchronous"/>

3.DI

詳しいことはDI/AOPを参照。

public class OrderModule : Ninject.Core.StandardModule

{

public override void Load()

{

Bind<IOrderStrategy>().To<OrderSynchronous>();

}

}

※xml設定ファイルを利用せず、タイプバインドする。

呼び出す先

IKernel kernal = new StandardKernel( new OrderModule() );

Order order = kernal.Get<Order>();

order.Insert( new OrderInfo() );

4.CoC(Convention over Configuration) 設定より規約

設定ファイルサイズは肥大になると、性能・デバッグ・メンテナンスに影響がくるのを改善する。

Uses In Design

・Rails(Model, View, Controllerのパス名やクラス名など)

・ASP.NET MVC

public static WebRequest Create(Uri requestUri)

{

if (requestUri == null)

{

throw new ArgumentNullException("RequestUri is NULL");

}

string prefix = requestUri.Scheme.ToLower();

if (prefix == null)

{

throw new ArgumentNullException("Scheme is NULL");

}

if(prefix.Contains('.'))

{

prefix = prefix.Replace(".", string.Empty);

}

StringBuilder typeName = new StringBuilder();

typeName.Append("System.Net.");

typeName.Append(prefix.Substring(0, 1).ToUpper());

typeName.Append(prefix.ToLower().Substring(1, prefix.Length - 1));

typeName.Append("WebRequest");

return Activator.CreateInstance(Type.GetType(typeName.ToString())) as WebRequest;

}

呼び出す先

WebRequest myRequest = WebRequest.Create("http://www.google.com");

同じ:WebRequest myRequest = new System.Net.HttpRequest();

WebRequest myRequest = WebRequest.Create("ftp://www.google.com");

同じ:WebRequest myRequest = new System.Net.FtpRequest();

WebRequest myRequest = WebRequest.Create("net.tcp://www.google.com");

同じ:WebRequest myRequest = new System.Net.NettcpRequest();