开发者

When some methods will not be used/not implemented, use an Interface or Abstract Class?

开发者_运维技巧

I have a project where quite a few functions and variable getters will be defined, abstractly. My question is should I use an abstract class for this(with each function throwing NotImplementedException), or should I just use an interface? Or should I use both, making both an interface and then an abstract class implementing the interface?

Note, even though all of these functions and such may be defined, it does not mean they will all be used in all use cases. For instance, AddUser in an authentication class may be defined in an interface, but not ever used in a website due to closed user sign up.


In general, the answer to the question of whether or not to use inheritance or an interface can be answered by thinking about it this way:

When thinking about hypothetical implementing classes, is it a case where these types are what I'm describing, or is it a case where these types can be or can do what I'm describing?

Consider, for example, the IEnumerable<T> interface. The classes that implement IEnumerable<T> are all different classes. They can be an enumerable structure, but they're fundamentally something else (a List<T> or a Dictionary<TKey, TValue> or a query, etc.)

On the other hand, look at the System.IO.Stream class. While the classes that inherit from that abstract class are different (FileStream vs. NetworkStream, for example), they are both fundamentally streams--just different kinds. The stream functionality is at the core of what defines these types, versus just describing a portion of the type or a set of behaviors that they provide.

Often you'll find it beneficial to do both; define an interface that defines your behavior, then an abstract class that implements it and provides core functionality. This will allow you to, if appropriate, have the best of both worlds: an abstract class for inheriting from when the functionality is core, and an interface to implement when it isn't.

Also, bear in mind that it's still possible to provide some core functionality on an interface through the use of extension methods. While this doesn't, strictly speaking, put any actual instance code on the interface (since that's impossible), you can mimic it. This is how the LINQ-to-Objects query functions work on IEnumerable<T>, by way of the static Enumerable class that defines the extension methods used for querying generic IEnumerable<T> instances.

As a side note, you don't need to throw any NotImplementedExceptions. If you define a function or property as abstract, then you don't need to (and, in fact, cannot) provide a function body for it within the abstract class; the inheriting classes will be forced to provide a method body. They might throw such an exception, but that's not something you need to worry about (and is true of interfaces as well).


Personally, I think it depends on what the "type" is defining.

If you're defining a set of behaviors, I would recommend an interface.

If, on the other hand, the type really defines a "type", then I'd prefer an abstract class. I would recommend leaving the methods abstract instead of providing an empty behavior, though.


Note, even though all of these functions and such may be defined, it does not mean they will all be used in all use cases.

If this is true, you should consider breaking this up into multiple abstract classes or interfaces. Having "inappropriate" methods in the base class/interface really is a violation of the Liskov Substitution Principle, and a sign of a design flaw.


If you're not providing any implementation, then use an interface otherwise use an abstract class. If there are some methods that may not be implemented in subclasses, it might make sense to create an intermediate abstract class to do the legwork of throwing NotSupportedException or similar.


One advantage of abstract classes is that one can add to an abstract class new class members whose default implementation can be expressed in terms of existing class members, without breaking existing inheritors of that class. By contrast, if any new members are added to an interface, every implementation of that interface must be modified to add the necessary functionality.

It would be very nice if .net allowed for an interface to include default implementations for properties, methods, and events which did not make any use of object fields. From a technical standpoint, I would think such a thing could be accomplished without too much difficulty by having for each interface a list of default vtable entries which could be used with implementations that don't define all vtable slots. Unfortunately, nothing like that ability exists in .net.


Abstract classes should be used when you can provide a partial implementation. Use interfaces when you don't want to provide any implementation at all - just definition.

In your question, it sounds like there is no implementation, so go with an interface.

Also, rather than throwing NotImplementedException you should declare your method/property with the abstract keyword so that all inheritors have to provide an implementation.


@Earlz I think refering to this: Note, even though all of these functions and such may be defined, it does not mean they will all be used in all use cases. is directly related to the best way to 'attack' this problem.

What you should aim at is minimizing the number of such functions so that it becomes irrelavant (or at least not that important) if you use either or. So improve the design as much as you can and you will see that it really doesn't matter which way you go.

Better yet post a high level of what you are trying to do and let's see if we can come up together with something nice. More brains working towards a common goal will get a better answer/design.


Another pattern that works in some situations is to create a base class that is not abstract. Its has a set of public methods that define the API. Each of these calls a Protected method that is Overideable. This allows the derived class to pick and choose what methods it needs to implement. So for instance

 public void AddUser(object user)
    {
        AddUserCore(user);
    }

    protected virtual void AddUserCore(object user)
    {
        //no implementation in base
    }
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜