Шаблоны для внедрения зависимостей
Я специально использую C# с Ninject, но проблема выходит за рамки только Ninject. Моя проблема в том, что у меня есть несколько классов с разными аргументами конструктора плюс введенные. Я знаю, что могу использовать kernel.Get<MyObject>(constructor args here)
создавать экземпляры объектов. Это не правильно для меня, так как у меня есть ядро повсюду. Я приложу все усилия, чтобы перечислить примеры ниже.
Что у меня сейчас:
public interface IStore<T>
{
void CommitToDatabase(T item);
}
public abstract class Thing
{
private IStore<Thing> _store;
protected Thing(object key, IStore<Thing> store)
{
Key = key;
_store = store;
}
public object Key { get; private set; }
public virtual void Update()
{
_store.CommitToDatabase(this);
}
}
public class Person :Thing
{
public Person(object key, string name, int age, IStore<Thing> store)
: base(key, store)
{
Name = name;
Age = age;
}
public string Name { get; private set; }
public int Age { get; private set; }
}
public class Car :Thing
{
public Car(object key, int year, string make, string model, IStore<Thing> store)
: base(key, store)
{
Year = year;
Make = make;
Model = model;
}
public int Year { get; private set; }
public string Make { get; private set; }
public string Model { get; private set; }
}
Я знаю, в Ninject я могу сделать следующее:
kernel.Get<Car>(new ConstructorArgument("key", 1), new ConstructorArgument("year", 2010), new ConstructorArgument("make", "Astin Martin"), new ConstructorArgument("model", "Vanquish"));
но мне это не кажется правильным. Я думал о том, чтобы изменить его на метод Initialize, но я не уверен, является ли это наилучшей практикой или есть лучший способ.
Возможные новые вещи:
public interface IStore<T>
{
void CommitToDatabase(T item);
}
public abstract class Thing
{
private IStore<Thing> _store;
protected bool _isInitialised;
protected Thing(IStore<Thing> store)
{
Key = null;
_store = store;
_isInitialised = false;
}
public object Key { get; private set; }
public virtual void Initialize(object key)
{
if (!_isInitialised) {
Key = key;
_isInitialised = true;
}
}
public virtual void Update()
{
_store.CommitToDatabase(this);
}
protected bool IsInitialised()
{
return _isInitialised;
}
}
public class Person :Thing
{
public Person(IStore<Thing> store)
: base(store)
{
Name = string.Empty;
Age = int.MinValue;
}
public string Name { get; private set; }
public int Age { get; private set; }
public void Initialize(object key, string name, int age)
{
if (!base.IsInitialised()) {
Name = name;
Age = age;
}
base.Initialize(key);
}
}
public class Car :Thing
{
public Car(IStore<Thing> store)
: base(store)
{
Year = 0;
Make = "Ford";
Model = "Model T";
}
public int Year { get; private set; }
public string Make { get; private set; }
public string Model { get; private set; }
public void Initialize(object key, int year, string make, string model)
{
if (!base.IsInitialised()) {
Year = year;
Make = make;
Model = model;
}
base.Initialize(key);
}
}
Вопрос: Является ли "Возможные новые вещи" обычной практикой, плохой идеей, хорошей идеей с плохой реализацией или есть лучший способ сделать это вообще?
1 ответ
Вы не должны вводить IStore в свой DTO. Они должны быть простыми предметами. Вместо того, чтобы вводить IStore<IThing>
в классы, которые в настоящее время называют Update
и позвонить CommitToDatabase
оттуда.
например
public class PersonService
{
private readonly IStore<Person> store;
public PersonService(IStore<Person> store)
{
this.store = store;
}
public void CreatePerson(string name, int age)
{
var person = new Person(name, age);
this.store.CommitToDatabase(person);
}
}
Также DTO, такие как Person, не должны создаваться с использованием контейнера IoC. Получите их из своего слоя постоянства, создайте их с помощью AutoMapper или создайте их с помощью new
, Но не используйте контейнер IoC для них. У них не должно быть никаких зависимостей.