0

I do believe that my question is similar to: Is it OK for interfaces to depend on concrete classes? and see/understand what the answer explains about how the dependency-inversion principle should be followed. But I am interested in a slight variation of this question. Would it be acceptable to define an interface containing objects from framework/OS libraries?

An answer in the question I am referencing mentions a bit about how Java libraries are believed to be stable and more or less acceptable to include in an interface, but they don't fully discuss this aspect. In my case I am using C# and would like to create an interface that accepts a CancellationToken to have the object support cancellation, for example. Would it be an acceptable practice to use this .NET object on my interface?

6
  • 1
    Design your interfaces from the consumer's perspective. If your consumer is dealing in or expecting concrete classes then yes it is absolutely fine. Start thinking of interfaces as extension points, not as ways of trying to make X totally independent of Y - that is a fool's errand and largely missing the point.
    – Ant P
    Commented Oct 12, 2017 at 15:39
  • This question is absurd. Concrete classes are made to be used. Interfaces such as you describe add unnecessary complexity. Commented Oct 12, 2017 at 17:23
  • @FrankHileman Can you explain what you mean, preferably in an answer?
    – Snoop
    Commented Oct 12, 2017 at 17:49
  • You are adding interfaces that serve no purpose, as there are existing classes that do the same thing. Interfaces are only for situations where you need multiple inheritance. Commented Oct 12, 2017 at 22:36
  • @FrankHileman What do you mean? I am askiing if it's okay to use concretes, I'm not adding any interfaces for no reason.
    – Snoop
    Commented Oct 13, 2017 at 11:08

3 Answers 3

3

The reasons this might be a bad idea are because you want your program to work even when the library interface changes, or at the very least, you need only change little in your program for it to work.

The likelihood that you shoot yourself in the foot increase with every direct reference to the library you make. Sometimes you must, but if you were to minimize calls through an interface of your own making, you've essentially added a layer to soften the coupling. So long as the library makes reasonable changes offering alternative methods, you can more often then not make due without even altering your program beyond the interface class handling concrete classes.

Similarly, the objects returned from a library may be important throughout your program. You should encapsulate those instances in your own classes and offer only methods that you use internally. This pattern is sometimes called Facade. Whether or not your facade acts like the library class is entirely up to you, but you're encouraged to simplify where you can.

Hope that helps!

8
  • 1
    Excellent advice for people who wish to bloat their code. Commented Oct 12, 2017 at 17:22
  • 1
    @FrankHileman And I'd be in agreement with you if the intention is to dedicate no more than an afternoon for a side project. Otherwise, it isn't best practice, nor should it be encouraged if a program is meant to be made for long-term usage. Sometimes maintenance costs are more important than having to spend an extra hour to encapsulate library classes.
    – Neil
    Commented Oct 16, 2017 at 11:49
  • While I agree that isolation, abstraction can be important when attempting to produce portable code, producing portable code is generally an expensive undertaking, only performed when the expense is justified (i.e. you need the abstraction layer). Differences between API's usually make this difficult. There was no indication in the question that such a layer was needed. Commented Oct 16, 2017 at 23:38
  • Creating interfaces that mimic concrete classes is worst practice, not best practice. They serve no purpose. Commented Oct 16, 2017 at 23:40
  • @FrankHileman Perhaps you disagree with the benefits of such encapsulation, and I respect that, though to say it serves no purpose makes me think you don't understand why this might be beneficial in the first place. The reason behind mentioning the layering in my answer is a proper solution to the problems that arise directly using library APIs and specifically library instances as it provides a buffer. It doesn't serve to make the program faster or simpler, no, but like loose coupling, it serves to make your code flexible and maintainable.
    – Neil
    Commented Oct 17, 2017 at 7:20
1

As often before the answer is - it depends.

It depends entirely on which consumers you support and where this concrete class is from. If you require consumers to take in an dll they don't need or want just to implement your interface then it would be a very bad idea.

Lets say you made an interface ISqlSomething and you have implementations ISqlServiceSomething and MySqlSomething. The implementations are in different assemblies so they don't need dependencies on a db they don't use. In that case it would be a very bad thing to put MySql or SqlServer specific things in the interface.

In your example, if you don't support any use cases where CancelationToken is not available then you should be fine. One such example could be if you wanted support an old version of the framework. In that case you should another solution.

1

Yes, I would say that CancellationToken, Exception, Task, List etc are acceptable to expose.

Obviously you are requiring that those who use your library also use the libraries which contain these classes, and with .net Standard now out you might want to check what is supported by what! (System.Threading is in .Net Standard 2.0)

https://github.com/dotnet/standard/blob/master/docs/versions/netstandard2.0.md

But these kind of objects are very likely to be in use already in most .net projects.

8
  • Minor point: do not use List directly, especially in interfaces. Use IList instead.
    – David Arno
    Commented Oct 12, 2017 at 14:28
  • 1
    @DavidArno why do that?
    – GHP
    Commented Oct 12, 2017 at 18:07
  • @Graham, if the interface specifies List<T>, then that type must be supplied. But if it for example that interface defines List<string> ToStringList<T>(List<T> list); then implementations are forced into using List unnecessarily. IEnumerable<string> ToStringList<T>(IEnumerable<string> list); leaves the implementer free to process any collection and return the result in a way that suits it.
    – David Arno
    Commented Oct 12, 2017 at 18:35
  • IEnumerable sure, but IList?
    – Ewan
    Commented Oct 12, 2017 at 18:45
  • @DavidArno as a side comment, arrays are one of the convenient things that can be cast to IList<T>. Commented Oct 13, 2017 at 1:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.