views:

68

answers:

3

I'm currently designing a small system and i'm currently using structureMap as IoC. I just recently got the point of interface segregation...and I'm wondering now.

If I have a certain business object, that will implement say, three interfaces... how should I handle this in the configuration and instatiation of code?

Assuming I have two interfaces in a simple scenario, for a service layer class called EmployeeServiceObject. IGenericEntity and IEmployeeServiceObject.

GenericEntity will provide the CRUD capabilities for the class, and IEmployeeServiceObject will provide resultsets for business queries/operations.

If on a Facade/Service Layer method, I have to use the EmployeeServiceObject class and actually use functionality from both interfaces...how should this be handled?

Initially I thought that the correct thing was to setup the configuration of the IoC to map IEmployeeServiceObject to EmployeeServiceObject, ask the factory for the object, and just cast it to IGenericEntity when i needed to use the CRUD functionality, but i'm not quite sure. It also does not seem right because I'd never be formally stating that the concrete class is actually implementing the interface that was not setup in the ioc container configuration.

and I definitely know that creating two instances of the same concrete class but asking for a different interface...sounds even worse.

How should this be handled?

+2  A: 

If I understand the question correctly, you have the following scenario (in C# code):

public interface IGenericEntity { /**/ }

public interface IEmployeeServiceObject { /**/ }

public class EmployeeServiceObject : IEmployeeServiceObject, IGenericEntity

If so, the fact that EmployeeServiceObject implements both interfaces is an implementation detail. You may have other implementations that implement each interface separately.

The point of the ISP is that each interface models a separate concern, so if you often find yourself in a situation where you need both IGenericEntity and IEmployeeServiceObject you should question whether the separation into two interfaces is meaningful.

Otherwise you should request each interface separately, because any attempt at casting would be breaking the Liskov Substitution Principle.

In the cases where you truly need both, you will need to request both:

public class Foo
{
    public Foo(IGenericEntity ge, IEmployeeServiceObject eso) { /**/ }

    // ...
}

In the case where you have one class (EployeeServiceObject) implementing both interfaces, you will need to tell the DI Container that this is the case. At this point, we are moving in to the area of container-specific details, so how you do that varies with each container.

For example, Windsor has the Forward method that lets you specify that requests for one interface is forwarded to another type.

In Poor Man's DI it's as simple as

var eso = new EmployeeServiceObject();
var f = new Foo(eso, eso);

It's always a good thing to understand how you would compose the dependency hierarchy with Poor Man's DI because it can give you valuable clues to how the container would understand the same thing.

Mark Seemann
Mark,You make a good point in that if I come up with a scenario in which I have to use methods from both interfaces (implemented by the same object) in the same method, then maybe the separation of concerns is not the most optimal and maybe both methods should belong in the same interfaces.I agree about breaking Liskov's principle if I cast..and in that scenario, I didn't even know if I was going to register the concrete class with the container two times, one for each interface.
silverCORE
Like you mention, if the scenario should come where I definitely need both, maybe stating both dependendies in the constructor is the way to go. Now then it would come to the specific IoC container implementation to see if it matches that the same concrete implementation is mapped to both interfaces and if it's going to reuse the instance, just internally casted to the second interface.Very good comment on thinking how it would be done with Poor man's DI.
silverCORE
A: 

If I may, before addressing the DI/IoC implementation, I would like to address your API. I think your pain points are trying to lead you to a better design.

The EmployeeServiceObject seems to have too many responsibilities. Consider the Single Responsibility Principle while creating your objects. In your description, the EmployeeServiceObject is both a facade/service layer and a CRUD layer. By assigning the interface for the CRUD operations(IGenericEntity), you are exposing your CRUD implementation to the consumer of your facade(IEmployeeServiceObject).

Given this situation and types you've described, please consider a different approach (I would also reconsider your type names to more accurately describe their purpose):

public interface IEmployeeServiceObject 
{
    // Service methods
    decimal GetSalary(string employeeId);
}

public class EmployeeServiceObject : IEmployeeServiceObject
{
    private IGenericEntity<Employee> _entity;

    public EmployeeServiceObject(IGenericEntity<Employee> entity)
    {
        _entity=entity;
    }

    public decimal GetSalary(string employeeId)
    {
        return _entity.Get(employeeId).Salary;
    }
}

public interface IGenericEntity<T>
{
    // CRUD Methods including...
    T Get(string id);
}

public class GenericEntity<T> : IGenericEntity<T> 
{
    T Get(string id){...}
}

Register the IEmployeeServiceObject/EmployeeServiceObject and the IGenericEntity/GenericEntity pairs with your container of choice. (StructureMap can register these types by convention.)

When you request the IEmployeeServiceObject from the container, the container will inject the GenericEntity into the EmployeeServiceObject's constructor prior to giving it to you.

In this way, you avoid the casting/registration issues you described. There is no need to force the container to work in a sub-optimal manner. Plus, your facade only exposes what is needed by its clients, and defers CRUD operations to another class (which does not need to be exposed to the clients).

Richard Cirerol
Mark. thanks for suggesting a different approach. Actually you're right in saying that the design is not the most optimal, The CRUD functionality shouldn't be exposed in a service layer, however, it's just a scenario that I came up with, similar to mine.As much as your design is totally valid, and definitely the best for the sample scenario that I provided, I still think there can be scenarios in which a programmer might need to use methods from both interfaces in the same object (registered with the container), and I want to know how this should be handled.
silverCORE
A: 

I didnt find how to close my question as duplicate...but I found exactly how to do what I needed in another stackoverflow question.

What Mark mentioned as the Forward method in Windsor, it also exists in StructureMap...and it appears it would be the right way to do things.

http://stackoverflow.com/questions/2363458/structuremap-singleton-usage-a-class-implementing-two-interface

silverCORE