6

I am maintaining an ASP.NET MVC project. In the project the original developer has an absolute ton of interfaces. For example: IOrderService, IPaymentService, IEmailService, IResourceService. The thing I am confused about is each of these is only implemented by a single class. In other words:

OrderService : IOrderService
PaymentService : IPaymentService

My understanding of interfaces has always been that they are used to create an architecture in which components can be interchanged easily. Something like:

Square : IShape
Circle : IShape

Furthermore, I don't understand how these are being created and used. Here is the OrderService:

public class OrderService : IOrderService
{
    private readonly ICommunicationService _communicationService;
    private readonly ILogger _logger;
    private readonly IRepository<Product> _productRepository;

    public OrderService(ICommunicationService communicationService, ILogger logger,
        IRepository<Product> productRepository)
    {
        _communicationService = communicationService;
        _logger = logger;
        _productRepository = productRepository;
    }
}

These objects don't seem be ever be created directly as in OrderService orderService = new OrderService() it is always using the interface. I don't understand why the interfaces are being used instead of the class implementing the interface, or how that even works. Is there something major that I am missing about interfaces that my google skills aren't uncovering?

Nick
  • 1,903
  • 2
  • 21
  • 40
  • 2
    Perhaps the idea was to use interfaces so that business objects can be substituted with something simple for unit testing (but never got that far)? – Ilia G Dec 09 '11 at 14:47
  • 2
    It does seem a bit of overkill if an interface is only implemented by a single class. Perhaps this was designing for a future that never came? – Polyfun Dec 09 '11 at 14:48
  • By saying "The thing I am confused about is each of these is only implemented by a single class" Do you refer to this: "public class OrderService : IOrderService"? If so, are there many places in the project where the constructor has things like Ilogger or the other interfaces as parameters? – Chris W Dec 09 '11 at 15:03
  • @ChrisW yes it does that everywhere in the project – Nick Dec 09 '11 at 15:13
  • Then it seems he's doing a pretty normal thing, constructor injection using an IoC Container. If you check global.asax you will probably find the setup code for the container, and the Binding code. – Chris W Dec 09 '11 at 15:33

5 Answers5

4

This particular design pattern is typically to facilitate unit testing, as you can now replace OrderService with a TestOrderService, both of which are only referenced as IOrderService. This means you can write TestOrderService to provide specific behavior to a class under test, then sense whether the class under test is doing the correct things.

In practice, the above is often accomplished by using a Mocking framework, so that you don't actually hand-code a TestOrderService, but rather use a more concise syntax to describe how it should behave for a typical test, then have the mocking framework dynamically generate an implementation for you.

As for why you never see 'new OrderService' in the code, it's likely that your project is using some form of Inversion of Control container, which facilitates automatic Dependency Injection. In other words, you don't have to construct OrderService directly, because somewhere you've configured that any use of IOrderService should automatically be fulfilled by constructing a singleton OrderService and passing it in to the constructor. There are a lot of subtleties here and I'm not exactly sure how your dependency injection is being accomplished (it doesn't have to be automatic; you can also just construct the instances manually and pass them in through the constructors.)

Dan Bryant
  • 27,329
  • 4
  • 56
  • 102
  • It iparticularly used from people too greedy to buy a proper unit testing framework - i.e. mostly a proper mock service that can mock non-interface or non virtual methods. Once you get a proper one you can actually write both, safe good designed classes as well as good unit tests. As well as mock static method calls and constructions. – TomTom Dec 09 '11 at 15:02
  • @TomTom, what's unsafe about only accessing a service through a well-defined interface? – Dan Bryant Dec 09 '11 at 15:04
  • Nothing, but unit tests in mock frameworks often go that far demanding methods to be fvirtual, where normal OOP practices would demand a sealed class. So one has to write bad classes to support a mocking framework. OR one implenments interfaces without need when they are not needed. I have ton of internal IOC and see no need to have an inteface JUST to be able to unit test another class where I can pss the class and mock the SEALED class when i need it. – TomTom Dec 09 '11 at 15:10
  • For example, make a SEALED OrderService and I can still mock it. Heck, I can mock the static "Instance" method to replace the returned valud with my mock instance ;) – TomTom Dec 09 '11 at 15:11
  • @TomTom, I definitely recommend sealing service classes, which is why interfaces are a good fit for encapsulating the service (since a sealed class can implement an interface.) They are easy to maintain with any halfway decent refactoring tools, so really the only objection is that it adds a few more files and lines of text to the source code. I personally feel this is a reasonable tradeoff. Static detouring tools are quite powerful, but using them to mock services that could have easily been encapsulated as interfaces strikes me as akin to using a sledgehammer to kill a fly. – Dan Bryant Dec 09 '11 at 15:27
  • Not always. Interfaces add significant maintenance overhead which sometimesi s not justified - especialyl not within one system or in a lbirary exposed to thrid parties. – TomTom Dec 09 '11 at 15:29
  • So, it looks like it is using Windsor for IoC (got me some reading to now). But as for the 1-1 relationship between the interfaces and the classes implementing them, should I continue in this fashion? Is this a part of the IoC methodology that I will uncover or is this mainly for the unit testing? – Nick Dec 09 '11 at 15:42
  • @Nick, it's not strictly necessary for IoC to use service interfaces (you can inject concrete classes directly), but it's quite typical. I would recommend continuing the pattern, even if not currently performing unit tests, for the sake of consistency. – Dan Bryant Dec 09 '11 at 16:33
1

That's not the only use of interfaces, in MVC they are being used to decouple contract from implementation. To understand about MVC you need to read up a bit on the related topics such as separation of concerns and inversion of control (IoC).The actual act of creating an object to be passed to OrderService constructor is handled by IoC container based on some predefined mapping.

mmix
  • 6,057
  • 3
  • 39
  • 65
1

These objects don't seem be ever be created directly as in OrderService orderService = new OrderService()

So waht?

Point is that SOMEONE calls the OrderService constructor and THE CALLER is respónsible for creating them. He hands them over.

I don't understand why the interfaces are being used instead of the class implementing the interface

Because you want not to know the class - it may change, be external, be configurable using an IOC container and the programmer decided to not require even a common base class. THe less assumptions you make about how someone implements used utility classes, the better.

Is there something major that I am missing about interfaces that my google skills aren't uncovering?

No, bu a good book about OO programming would help more than random google snippets. This baiscally falls into the architecture area and .NET basics (for the first part).

TomTom
  • 61,059
  • 10
  • 88
  • 148
  • 2
    Given the context I think interfaces are being abused here, fileable under YAGNI. Every time, instead of simply creating a class, the original author created an interface and then implemented that in a class. That's a bit bloated if you ask me: most classes will probably never be subject to another implementation. – CodeCaster Dec 09 '11 at 14:49
  • I'm not so sure, looking at the code snippet it's only services, loggers and reps which have interfaces - this implies (to me) an IoC container is being used. The users question regarding use of Interfaces in this project (the Square : IShape bit) again implies the project is only using interfaces for the injectable components. *But* this is a lot of "implying" and without looking at the project, one won't get a better view of whats going on. – Chris W Dec 09 '11 at 14:58
1

It's good practice to program against interfaces rather than objects. This question gives good reasons why, but some reasons include allowing the implementation to change (ex. for testing).

Just because there's currently only 1 class that implements the interface doesn't mean that it can't change in the future.

Furthermore, I don't understand how these are being created and used.

This is called dependency injection and basically means that the class doesn't need to know how or where to instantiate it's dependencies from, someone else will handle it.

Community
  • 1
  • 1
Lester
  • 4,243
  • 2
  • 27
  • 31
0

These are service interfaces, which encapsulate some kind of externality. You often have just a single implementation of them in your main project, but your tests use simpler implementations that don't depend on that external stuff.

For example if your payment service contacts paypal to verify payments, you don't want to do that in a test of unrelated code. Instead you might replace them with a simple implementation that always returns "payment worked" and check that the order process goes through, and another implementation that returns "payment failed" and check that the order process fails too.

To avoid depending on the implementation, you don't create instances yourself, you accept them in the constructor. Then the IoC container that creates your class will fill them in. Look up Inversion of Control.

Your project has probably some code that sets up the IoC container in its startup code. And that code contains information about which class to create when you want an implementation of a certain interface.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262