この問題に適したパターンはありますか?
-
06-07-2019 - |
質問
モデルと実装を可能な限り疎結合にしようとしていますが、結合が必要以上に近くなる可能性がある状況に直面しています。
すべてのインターフェイスを実装する「モデル」クラスの選択があります。さらに、いくつかの関数を提供する「データアクセス」クラスがあり、そのうちの1つは整数ルックアップ値を完全な「オブジェクト」表現にデコードします。
モデルクラス内で、モデルがデータアクセスクラスについて知る必要なく、これらのデコードされた値へのアクセスを提供したい。
簡単な例は次のとおりです。
/// Core classes --
class Car : ICar
{
public int MakeId { get {...} set { ... } }
public IMakeInfo Make { get {...} }
public string Registration { get { ... } set { ... } }
public int CurrentOwnerId { get { ... } set { ... } }
public IPerson CurrentOwner { get { ... } }
}
class MakeInfo : IMakeInfo
{
public string Name { ... }
public int Id { ... }
public decimal Weight { ... }
// etc etc
}
/// Data Access Classes --
class ResolveMake
{
public IMakeInfo GetMakeInfo(int id)
{
// Implementation here...
}
}
Car
クラスを有効にして、ResolveMakeクラスを直接認識せずに、消費するクラスに IMakeInfo
オブジェクトを提供するにはどうすればよいですか? Carクラスで作業している実際のインスタンスは、ResolveMakeクラスと同じ名前空間になく、そのインスタンスへの参照は含まれていません。
私のオプションのいくつか:
-
GetMakeInfo
メソッドのインスタンスを提供できるCar
にデリゲートを実装します。 - いくつかの種類の依存性注入
- CarをResolveMakeに密接に結合し、完了です。
- その他のオプション?
どんな提案でも歓迎します!
解決
namespace CarStuff
{
class Car : ICar
{
public int MakeId { get {...} set { ... } }
// no Make property...
public string Registration { get { ... } set { ... } }
public int CurrentOwnerId { get { ... } set { ... } }
public IPerson CurrentOwner { get { ... } }
}
}
namespace MakeExts
{
class ResolveMake
{
public static IMakeInfo Make(this Car myCar)
{
//implementation here
}
}
}
その他:
using MakeExts;
Car c = new Car();
Console.WriteLine(c.Make().ToString());
編集:.NET 2.0で拡張メソッドを使用するには、次のようなものが必要です。
- http://kohari.org/2008/ 04/04 / extension-methods-in-net-20 /
- http:// www .danielmoth.com / Blog / 2007/05 / using-extension-methods-in-fx-20.html
基本的に、次を含むクラス:
namespace System.Runtime.CompilerServices
{
class ExtensionAttribute : Attribute
{
}
}
および" using System.Runtime.CompilerServices"関連する場所に散在しています。
他のヒント
私には依存性注入のように聞こえます。 MS PP Unityと、コンストラクター注入、メソッドおよびプロパティ注入の両方で、同様のことを行いました。 Carクラスには、IMakeInfo ... exampleの何らかのインジェクションがあります:
[InjectionMethod]
public void Initialize([Dependency] IMakeInfo makeInfo)
{
this.MakeInfo = makeInfo;
}
CarクラスにはIMakeInfoを返すMakeプロパティがあるため、すでに情報を提供しているように見えます。だから私はあなたの問題は車に返される値をどのように提供するのかということだと仮定するのは正しいですか?
この場合、おそらくファクトリーメソッドの作成を確認したいでしょう。車とResolveMakeについて。
類推すると、車は明らかにget_MakeがIMakeInfoと呼ばれるまでに知る必要があります。私はまた、車の重要な特徴を作ることを検討します。したがって、IMakeInfoをCarコンストラクターに渡す(おそらくIOCを使用する)のは非常に合理的だと思います。これが実際のコードとよく似ている場合(各「車」には単一の固有の「IMakeInfo」があります)、私はこれを使います。
また、Johanが言ったように、オプションのIOCでセッターを使用することもできます。私がコンストラクタを好む理由は、すべて" Car" " Make"が必要です。
最後に(私が働いていた制約を考えると)私は実際に上記のテーマの多くのバリエーションを使用しました。
循環参照が発生するため、データアクセスレイヤーへの参照を回避する必要があったため、デリゲートと「工場」コードで何かをすることになりました。元のシナリオに合わせて、次のことを行いました。
class Car
{
public void SetLookupProvider(ILookupProvider value) { _lookupProvider = value; }
public IMakeInfo Make { get { return _lookupProvider.ResolveMake(MakeId); } }
....
}
interface ILookupProvider
{
IMakeInfo ResolveMake(int id);
}
class LookupProvider
{
public delegate IMakeInfo ResolveMakeDelegate(int id);
public ResolveMakeDelegate ResolveMakeDel { set { _resolvemake = value; } }
public IMakeInfo ResolveMake(int id){ return _resolvemake(id); }
}
その後、ファクトリーメソッドで...
ICar returnedObject = new Car(blah, foo, bar, etc);
ILookupProvider luprovider = new LookupProvider();
luprovider.ResolveMakeDel = DataAccessLayer.FunctToGetMakeInfo;
(Car)returnedObject.SetLookupProvider(luprovider).
今、これが最もきれいなソリューションではないことを認めた最初の人です(3.0コンパイラにアクセスしていた場合、Extensionメソッドを使用していましたが)。 (私の状況では、循環参照地獄を防いだ...)。 Carクラスは、結果を取得する方法を知る必要はなく、最初にCarオブジェクトを生成するファクトリメソッドのみが、データアクセス層に結合されます。
まだ回答をマークしていませんが、さらに多くの人に投票させてから、最高の投票をさせます-特に彼らはすべて有効な回答だと思うのでこのインスタンス)。