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();