Now the title might seem like the question has been asked before but let me explain my situation and you’ll see why I am asking this question.
Let’s consider this interface :
public interface IListChangedListener {
public event EventHandler ItemAdded;
public event EventHandler ItemRemoved;
}
If someone wants to implement this interface, they would have to check if ItemAdded
is null and only if it is not null, they would call it. Well, I want to simplify their job by giving an in built function which will do the same. Just calling that function will check if the corresponding event is null, and if it isn’t, it’ll fire its corresponding event.
The problem is, this is an interface. So I can’t define a method. So I thought I might go with an abstract class. But considering the situation, it would be best suited to make this as an interface rather than an abstract class.
So do I just drop the idea of giving an in built function? Or do I make it an abstract class? Which better suits the situation? I am having a tough time deciding which one to use. Some help please?
9
What would be best is to have a mixin, but unfortunately C# doesn’t include this concept. In the absence of mixins, I’d pick an interface over an abstract class almost every time, and definitely in this case. Whatever functionality has to be offered to derived classes, it can be offered in form of helper objects and utility functions. Favoring composition over inheritance is my favorite design principle.
In this specific case we should be able to have it both though. I would definitely have the interface, as you defined it. The interface should be used by all consumers and other classes in your utility. For the convenience of your users (developers) I would also have a default implementation of the interface that can be used as a base class.
public interface IListChangedListener {
public event EventHandler ItemAdded;
public event EventHandler ItemRemoved;
}
public class ListChangedListener : IListChangedListener {
public event EventHandler ItemAdded;
public event EventHandler ItemRemoved;
public void FireItemAdded(...) {
if (ItemAdded != null)
ItemAdded(...)
}
public void FireItemRemoved(...) {
if (ItemRemoved != null)
ItemRemoved(...)
}
}
This way a developer can either derive from the ListChangedListener
class, or implement the IListChangedListener
interface directly, depending on circumstances. In the end of the day what counts is that the listener class they provide implements the IListChangedListener
interface.
Would that work?
2
As usual:
-
If you need to implement some methods, the interface is not a solution. You have to use an abstract class.
-
On the other hand, if you need to describe the behavior, especially in a context where classes which have this behavior might already have a parent class, you have to use an interface, since in C#, a class cannot have multiple parents.
If you need the benefits of both worlds, don’t use neither an interface, nor an abstract class, but have a separate object used within the objects.
In your case, you need to describe the behavior. The business logic brought by an eventual abstract class or a dedicated class is not that useful: it’s just a null check, nothing more. Therefore, the repetition of those null checks in different classes which implement the interface wouldn’t be a serious violation of DRY principle.
Agreed, most implementers will end up creating two methods which check for nullity and raise the event, but again, this is not that complicated to do (nor would the logic change over time).
From the comments, it appears that you are reinventing the wheel. In .NET Framework, there is already a class which does what you need: ObservableCollection<T>
.
It has nothing to do with WPF: it is a part of System.Collections.ObjectModel
namespace, the one which contains many things related to collections, including Collection<T>
itself, ReadOnlyCollection<T>
, etc. You can use those collections outside WPF, that is in a console application, a Windows Forms project or a website.
6
You should have both the interface and a class with a default implementation. For example, if you have an IDog interface, it could have a Bark() method defined. A separate Voicebox class could provide the default implementation. This could look like this:
public interface IDog
{
public void Bark();
}
public class VoiceBox
{
public void Bark()
{
// Do bark
}
}
class Poodle : IDog
{
private Voicebox voicebox = Voicebox.GetDefault();
public Bark()
{
voicebox.Bark();
}
}
This way, the client is not required to use your Voicebox class, but they are still required to make their dog bark somehow. If they want to use your default implementation, then they can use the Voicebox class. Of course, you can make the bark method virtual in the Voicebox class if it needs to be overridden by subclasses.
2