开发者

OOD using IoC containers - how to construct dependant objects?

开发者 https://www.devze.com 2023-03-27 16:15 出处:网络
I am trying to get better with IoC,DI and OOD for better testability and looser coupling. So when we design classes with heavy use of IoC and DI we can endup with classes with multiple dependencies f

I am trying to get better with IoC,DI and OOD for better testability and looser coupling.

So when we design classes with heavy use of IoC and DI we can endup with classes with multiple dependencies for example

class Processor
{
    private IService1 m_Service1;
    private IService2 m_Service2;
    private IService3 m_Service3;

    //approach 1 
    public Processor(IService1 service1, IService2 service2, IService3 service3)
    {
        m_Service1 = service1;
        m_Service2 = service2;
        m_Service3 = service3;
    }
    //approach 2
    public Processor(IContainer conta开发者_如何学Ciner)
    {
        m_Service1 = container.Resolve<IService1>();
        m_Service2 = container.Resolve<IService2>();
        m_Service3 = container.Resolve<IService3>();
    }

    //approach 3
    public delegate Processor Factory();

}

Im thinking what should be the usual approach here. We can leave constructor with 3 parameters, but if we are building app using autofac (for example) most likely it will rarely be used other than by resolving types from some container instance like

    Processor proc = new Processor(
 container.Resolve<IService1>(),
 container.Resolve<IService2>(),
 container.Resolve<IService3>());

so I am thinking maybe approach 2 is better, when we depend on multiple types from container. Anyway we will have to add reference to autofac somewhere, so any reasons not to do it now?

Autofac also provides delegate factory method approach

http://code.google.com/p/autofac/wiki/DelegateFactories

var processorFactory = container.Resolve<Processor.Factory>();
Processor processor = processorFactory.Invoke();

So we have also approach 3 - we will not use constructors to create our class instances, instead we will be calling resolved delegate from container and it will resolve dependencies for us.

Since im fairly new to IoC its hard to say when we should use 1,2,3. They have advantages and disadvantages.

I think generally if class has 1 dependency we can probably always use approach 1.. other than that I am really not sure what to choose and when.

UPDATE i have read about service locator anti pattern but Ive come up with 4th (or true 3rd approach)

its close to ServiceLocator except its not, we pass an object that looks like this

public class ServiceLocatorObject
{
        private IService1 m_Service1;
        private IService2 m_Service2;
        private IService3 m_Service3;
        public IService1 Service1 {get {return m_Service1;}}
        public IService2 Service2 {get {return m_Service2;}}
        public IService3 Service3 {get {return m_Service3;}}

        public ServiceLocatorObject(IService1 service1, IService2 service2, IService3 service3)
        {
            m_Service1 = service1;
            m_Service2 = service2;
            m_Service3 = service3;
        }
}

And now we create

//approach 4
public Processor(ServiceLocatorObject servicesToUse)
{
    m_Services = servicesToUse;
}

Now we have decoupled our class from service implementations and its clear what real dependencies it needs (if we assume all services availabe on passed object are required) because we aren't passing a container that can contain 100 implementations. And that object can be even reused if that 3 service combination might be required in some another class in our application. So we are using constructor DI not ServiceLocator pattern. interface is clear and not overloaded with dependencies, new class might be a good reuse candidate.

What would you say about this one?


The service location pattern is often considered an anti-pattern these days (using container.Resolve and injecting the container).

After MUCH struggling with this concept myself and trying to decide if I like it or hate it, I've come to the personal realization that I agree service location is an anti-pattern - because it obfuscates the interdependencies which exist and which are a core concept of OOP.

Have a read here: http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

I actually LIKE that fact that in option 1, Process CLEARLY expresses its dependency on each of the services it lists are parameters in the constructor. It makes the dependencies very obvious....and further I think it helps promote good design.

Just saying Processor takes an IContainer doesn't tell us very much...and thus you need to take a much closer look to identify interdependencies.


The answer given by JeffN825 is correct, but I'd like to add to it that you'd never create a new Processor instance using a container like this:

Processor proc = new Processor(
    container.Resolve<IService1>(),
    container.Resolve<IService2>(),
    container.Resolve<IService3>());

Rather, you'd let the container auto-wire the dependencies and resolve it one go:

Processor proc = container.Resolve<Processor>();


This is not about number of dependencies, nor a per class decision. Approach 2 introduces a new dependency, but if you want to rely on an IoC container, than it is a good approach. Approach 3 is like the second, but let's you do some stuff in the Factory in future. Approach 1 is simplest, doesn't rely on anything and should be used for dependencies which you wouldn't usually manage through IoC container.

0

精彩评论

暂无评论...
验证码 换一张
取 消