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?

  • 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 Oct 12 '17 at 15:39
  • This question is absurd. Concrete classes are made to be used. Interfaces such as you describe add unnecessary complexity. – Frank Hileman Oct 12 '17 at 17:23
  • @FrankHileman Can you explain what you mean, preferably in an answer? – Snoop Oct 12 '17 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. – Frank Hileman Oct 12 '17 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 Oct 13 '17 at 11:08
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!

  • 1
    Excellent advice for people who wish to bloat their code. – Frank Hileman Oct 12 '17 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 Oct 16 '17 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. – Frank Hileman Oct 16 '17 at 23:38
  • Creating interfaces that mimic concrete classes is worst practice, not best practice. They serve no purpose. – Frank Hileman Oct 16 '17 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 Oct 17 '17 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.

  • Minor point: do not use List directly, especially in interfaces. Use IList instead. – David Arno Oct 12 '17 at 14:28
  • 1
    @DavidArno why do that? – Graham Oct 12 '17 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 Oct 12 '17 at 18:35
  • IEnumerable sure, but IList? – Ewan Oct 12 '17 at 18:45
  • @DavidArno as a side comment, arrays are one of the convenient things that can be cast to IList<T>. – Frank Hileman Oct 13 '17 at 1:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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