私は常に追加しているクラスを持っています。
public class OrderRepository{
public void Add(IEnumerable<Order> orders){}
public void Update(IEnumerable<Order> orders){}
public void Remove(IEnumerable<Order> orders){}
public void Expedite(IEnumerable<Order> orders){}
public void GetOrderData(Order order, DateTime start, DateTime end)
etc...
}
これらすべての新機能が追加されているため、このクラスは開閉式ではないことに気付きました。そこで、これらの関数を Request オブジェクトにカプセル化することで、この変更に対してこのクラスを閉じることを考えました。私は次のようなものになります:
public abstract class RequestBase{}
public class AddRequest : RequestBase{}
etc...
public class OrderRepository{
public void ProcessRequest(RequestBase request){}
}
これにより、 OrderRepository が拡張用に開かれ、変更用に閉じられます。ただし、これに関していくつかの問題にすぐに遭遇しました。
1.) リクエストが操作する必要があるデータは、ユーザー提供 (実行時) と依存性注入提供の両方です。明らかに、1 つのコンストラクターで両方を満たすことはできません。私はできません:
public class AddRequest{
public AddRequest(IEnumerable<Order> orders, int UserSuppliedContextArg1, DependencyInjectionArg1, DependencyInjectionArg2);
}
そしてそれを呼び出します。DIフレームワークがオブジェクトを「部分的に」構築し、残りは私に任せる方法が必要です。しかし、それを行う方法はありません。この概念を「変数コンストラクター インジェクション」と呼んだブログを見ました。
2.) 次に考えたのは、これを 2 つの別々のクラスに分割することでした。ユーザーは RequestContext を作成して入力し、それをリポジトリに渡します。リポジトリは、そこから RequestProcessor (より適切な名前を思いつきません) を作成します。私は次のことを考えました:
public abstract class RequestContextBase<T> where T : RequestProcessorBase{}
public class AddRequestContext : RequestContextBase<AddRequestProcessor>
public class OrderRepository{
public void ProcessRequest<T>(RequestBase<T> request){
var requestProcessor = IoC.Create<T>();
}
}
それは良い第一歩でした。ただし、リクエスト プロセッサには、保存している正確なタイプのコンテキストが必要ですが、ここにはありません。型の辞書を型に使用することもできますが、それは Open-Closed であるという目的を無効にします。そのため、次のようなことをしなければならなくなります。
public class RequestProcessorBase<TRequestContext, TRequestProcessorBase> where TRequestContext : RequestContextBase<TRequestProcessorBase>
これは奇妙で、私は通常、奇妙に繰り返されるテンプレート パターンが好きではありません。さらに、名前付けの問題かもしれませんが、ユーザーがコンテキストを埋めて、それをリクエストするように私に依頼するという考えは奇妙に思えます。
3.) 上記のすべてを取り除き、次のものを用意することを考えました:
public AddRequest{
public AddRequest(DependencyInjectionArg1, DependencyInjectionArg2, ...){}
public void PackArgs(UserSuppliedContextArg1, UserSuppliedContextArg2, UserSuppliedContextArg3, ...){}
}
これは悪くありませんが、API は醜いです。このオブジェクトのクライアントは、いわばそれを 2 回「構築」する必要があります。また、PackArgs を呼び出すのを忘れた場合は、何らかの例外をスローする必要があります。
続けることもできますが、これらは現時点で最も混乱している問題です。何か案は?