のために変更する必要がないことを保証しますこれは最高のいくつかのコードを用いて実証された - 私は例がこの問題を回避基づいてSimpleInjectorを使用します。
public interface IRepository
{
void Submit();
}
public interface IRepository<T> :IRepository where T : class { }
public abstract class GenericRepository<T> : IRepository<T> where T : class { }
とUnitOfWork
public interface IUnitOfWork
{
void Register(IRepository repository);
void Commit();
}
は各Repository
がUnitOfWork
に自身を登録する必要があり、これはそれがあることを確認するために、抽象親クラスGenericRepository
を変更することで行うことができますRepository
抽象化で開始行わ:
public abstract class GenericRepository<T> : IRepository<T> where T : class
{
public GenericRepository(IUnitOfWork unitOfWork)
{
unitOfWork.Register(this);
}
}
からの各実Repository
継承:
public class Department { }
public class Student { }
public class DepartmentRepository : GenericRepository<Department>
{
public DepartmentRepository(IUnitOfWork unitOfWork): base(unitOfWork) { }
}
public class StudentRepository : GenericRepository<Student>
{
public StudentRepository(IUnitOfWork unitOfWork) : base(unitOfWork) { }
}
はUnitOfWork
の物理的な実装に追加すると、すべてのセットです:
public class UnitOfWork : IUnitOfWork
{
private readonly Dictionary<string, IRepository> _repositories;
public UnitOfWork()
{
_repositories = new Dictionary<string, IRepository>();
}
public void Register(IRepository repository)
{
_repositories.Add(repository.GetType().Name, repository);
}
public void Commit()
{
_repositories.ToList().ForEach(x => x.Value.Submit());
}
}
コンテナの登録が自動的にすべてピックアップするように設定することができます定義されたインスタンスIRepository
を生涯有効範囲に登録して、トランザクションの存続期間中存続するようにします。
public static class BootStrapper
{
public static void Configure(Container container)
{
var lifetimeScope = new LifetimeScopeLifestyle();
container.Register<IUnitOfWork, UnitOfWork>(lifetimeScope);
container.RegisterManyForOpenGeneric(
typeof(IRepository<>),
lifetimeScope,
typeof(IRepository<>).Assembly);
}
}
DIを中心に構築されたこれらの抽象化とアーキテクチャでは、UnitOfWork
があり、すべてのサービス呼び出しでインスタンス化されたすべてのRepository
があり、すべてのリポジトリが定義されているコンパイル時間の検証があります。あなたのコードはopen for extension but closed for modificationです。
はすべてこれをテストするために - これらのクラスを追加 public class SomeActivity
{
public SomeActivity(IRepository<Department> departments) { }
}
public class MainActivity
{
private readonly IUnitOfWork _unitOfWork;
public MainActivity(IUnitOfWork unitOfWork, SomeActivity activity)
{
_unitOfWork = unitOfWork;
}
public void test()
{
_unitOfWork.Commit();
}
}
コードの行に対してブレークポイントを置きBootStrapper.Configure()
//register the test classes
container.Register<SomeActivity>();
container.Register<MainActivity>();
にこれらの行を追加します。
_repositories.ToList().ForEach(x => x.Value.Submit());
そして、最後に、このConsoleテストコードを実行してください:
class Program
{
static void Main(string[] args)
{
Container container = new Container();
BootStrapper.Configure(container);
container.Verify();
using (container.BeginLifetimeScope())
{
MainActivity entryPoint = container.GetInstance<MainActivity>();
entryPoint.test();
}
}
}
コード停止はブレークポイントで実行され、アクティブなインスタンスはIRepository
であり、Submit()
はデータベースへの変更を待っています。
あなたは、トランザクションなどを処理するためにUnitOfWorkを装飾することができます。私は強力に譲歩します。この時点でNetJunkieは、これら2つの記事hereとhereを読むことをお勧めします。
コンストラクタインジェクションで['Lazy'](http://msdn.microsoft.com/en-us/library/dd642331.aspx)を使用すると、実際に使用するときにのみ読み込まれる問題がありますそれ?すべてのIoCコンテナが「レイジー」をサポートしているわけではありません。 –
実際にこれに何か利点はありますか?私は、別のオブジェクトの作成のための1つのオブジェクトの作成に代えています。私はリポジトリ(そのコンストラクタが文脈の依存関係を割り当てている)が作成されるときに大きなオーバーヘッドを必要とすることに疑いを持っています。 – rashleighp
はそれが行く方法だとは言っていませんが、コンストラクタインジェクションの問題は各リポジトリをインスタンス化するオーバーヘッドを招いていると言いました。 'レイジー'の作成は事実上何もありません。 –