WiiMaxx
WiiMaxx

Reputation: 5420

Who creates dependency injection object in the first place

I would like to know who (which object) creates the real object which gets dependeny injected.

To make it more understandable here my example code

IOrder:

interface IOrder
{
    int Id { get; set; }
    string Name { get; set; }
    bool SaveChanges();
}

Order:

public class Order : IOrder
{
    private IOrderRepository repository;

    public int Id { get; set; }
    public string Name { get; set; }

    public Order(IOrderRepository repository)
    {
        this.repository = repository;
    }

    public bool SaveChanges()
    {
        if (Id < 1)
            return repository.Save(this);
        else
            return repository.Update(this);
    }
}

Like we can see if i want to create an Orderobject i need to inject an some object which inherited from IOrderRepository

IOrderRepository:

interface IOrderRepository
{
    IList<IOrder> GetAll();
    IOrder GetById(int id);
    IList<IOrder> GetBySomeRefId(int SomeRefId);
    bool Save(IOrder order);
    bool Update(IOrder order);
}

OrderRepository:

public class OrderRepository : IOrderRepository
{
    public IList<IOrder> GetAll()        {        }

    public IOrder GetById(int id)        {        }

    public IList<IOrder> GetBySomeRefId(int SomeRefId)        {        }

    public bool Save(IOrder order)        {        }

    public bool Update(IOrder order)        {        }
}

So here each Get method can and will inject it one class as a dependency, but if I need a new Order I have to do

var myOrderRepos = new OrderRepository();
var myNewOrder = new Order(myorderrepos);

and here is my problem where ever I have to write the

var myOrderRepos = new OrderRepository();

this class will break the separation ...

And this will basically every ViewModel which has a new command in it in this case NewOrderCommand.

OrderListVM snipped

    public ICommand NewOrderCommand
    {
        get { return newOrderCommand ?? (newOrderCommand = new RelayCommand(param => this.OnNewOrder())); }
    }

    public void OnNewOrder()
    {
        var myOrderRepos = new OrderRepository(); // <= tight coupling to OrderRepository
        var myNewOrder = new Order(myorderrepos); // <= tight coupling to Order
        var myOrderVM = new OrderVM(myNewOrder);
        myOrderVM.Show();
    }

How would you avoid this tight coupling?

Upvotes: 1

Views: 188

Answers (1)

CoderDennis
CoderDennis

Reputation: 13837

Why not put a CreateOrder method in your OrderRepository? Then your view models would get an IOrderRepository injected into them and be able to create orders from there.

I wouldn't make Order depend on IOrderRepository. That seems like the wrong level to place the dependency. When you've got a repository that's doing the saving and other work, then keeping objects like Order as simple data containers and putting all the actions in the repository provides a clean separation.

I find when using dependency injection (especially when combined with repositories), my view model and controller code very rarely contains the new keyword.

Dependency Injection is a pattern for managing coupling. As marc_s points out in his comment, you want to depend on the abstractions, not the implementations. It's OK for your classes to have dependencies, but it's better if the interface for each dependency is given to your class than for your class to create its own version of the implementation of that dependency. That's why I don't see new in my classes. I know if I'm newing up an object then that's probably a good place to stop and identify how to pass that dependency into the class instead of creating it right there. Of course, a repository creating new instances of the data object it manages is a good place for a call to new.

Here's some code to try to help explain what I'm talking about. While working through this, I noticed you're creating OrderVM instances within your OrderListVM. So, I've taken the dependency on IOrderRepository out of the VMs and introduced a ViewModel factory. You may also want a RepositoryFactory, but that seemed like too much to show here.

IOrder:

interface IOrder
{
    int Id { get; set; }
    string Name { get; set; }
}

Order:

public class Order : IOrder
{
    public int Id { get; set; }
    public string Name { get; set; }
}

IOrderRepository:

interface IOrderRepository
{
    IList<IOrder> GetAll();
    IOrder GetById(int id);
    IList<IOrder> GetBySomeRefId(int SomeRefId);
    bool Save(IOrder order);
    bool Update(IOrder order);
    IOrder CreateNewOrder();
}

OrderRepository:

public class OrderRepository : IOrderRepository
{
    ...
    public IOrder CreateNewOrder()
    {
        return new Order();
    }
}

OrderListVM:

public class OrderListVM 
{

    ViewModelFactory _factory;
    IEnumerable<IOrder> _orderList;

    public OrderListVM(ViewModelFactory factory, IEnumerable<IOrder> orders)
    {
        _factory = factory;
        _orderList = orders;
    }

    public void OnNewOrder()
    {
        var myOrderVM = _factory.GetOrderVM();
        myOrderVM.Show();
    }
}

OrderVM

public class OrderVM 
{
    IOrder _order;
    public OrderVM(IOrder order)
    {
        _order = order;
    }
}

ViewModelFactory

interface IViewModelFactory { ... }

public class ViewModelFactory : IViewModelFactory 
{
    IOrderRepository _repository;

    public ViewModelFactory (IOrderRepository repo)
    {
        _repository = repo;
    }

    public OrderListVM GetOrderListVM() {
        return new OrderListVM(this, _repository.GetAll());
    }

    public OrderVM GetOrderVM(IOrder order = null) {
        if (order == null) {
            order = _repository.CreateNewOrder();
        }
        return new OrderVM(order);
    }

}

Somewhere at the root of your project you'll have some bootstrap code that creates an instance of the ViewModelFactory and other dependencies and injects them into the classes that need them.

Upvotes: 2

Related Questions