Riz
Riz

Reputation: 6676

How to refactor duplicate event handling code

I have the following class that lets certain objects subscribe to a change event. The problem is that I also have classes B, and C that need this functionality that allow objects to subscribe to the same kind of thing. We certainly don't want to copy and paste this behaviour.

We've considered inheriting from a common base class, but all our classes including A, B, and C already inherit from a common BaseClass. And we don't want to add this behaviour to BaseClass because our other classes E,F,G that inherit from BaseClass don't need this behaviour.

Is there a better solution?

public class A : BaseClass
{

    /*other properties and code */

    public event EventHandler OnChange;
    private bool _hasChanged;
    public bool HasChanged
    {
        get { return _hasChanged; }
        set
        {
            _hasChanged = value;
            //only need to notify when we've changed.
            if (value)
            {
                if (OnChange != null)
                    OnChange(this, EventArgs.Empty);
            }
        }
    }
}

Upvotes: 4

Views: 324

Answers (4)

TalentTuner
TalentTuner

Reputation: 17556

What if we don't use inheritance for a moment?

1- Suppose , Instead of inheriting from a common base class, Compose your client class which requires event mechanism with a object which implement event mechanism.

Suppose our class is

 public class EventNotifier
{
    public event EventHandler OnChange;
    private bool _hasChanged;
    public bool HasChanged
    {
        get { return _hasChanged; }
        set
        {
            _hasChanged = value;
            //only need to notify when we've changed. 
            if (value)
            {
                if (OnChange != null)
                    OnChange(this, EventArgs.Empty);
            }
        }
    }
}

2-

 public class A
{
    private EventNotifier eventNotifier;
    public EventNotifier MyEventNotifier { get { return eventNotifier; } }

    public A()
    {
        eventNotifier = new EventNotifier();
    }


}

3- Now your users of class A ( class which is inherited / composed class A)

this is for if B contains A

 public class b
{
    A obj ;
    public b()
    {
        obj = new A();
        obj.MyEventNotifier.OnChange += new EventHandler(delegate { Console.WriteLine("Hi"); });
        obj. MyEventNotifier.HasChanged = true;
    }
}

Upvotes: 2

Homde
Homde

Reputation: 4286

Having a subclass for notifyable objects might be the way to go but it can be tricky with aspects multiplying that way into a wide range of different classes. Another way would to infact include it in your base class and define an interface for it, then you can simply tack on the interface for the relevant classes.

When running yous simply check if it's a IChangeable (or something) and only hook up to the event then

Upvotes: 0

Tim Lloyd
Tim Lloyd

Reputation: 38434

You could consider introducing an intermediary class between BaseClass and A,B,C that contains the common behaviour. In this way you will not be polluting E,F,G which do not need the behaviour.

             BaseClass
  -----------------------------
  |                           |
-----                   NotifyBaseClass
E,F,G                         |
                            -----
                            A,B,C

NB Although AOP looks yummy I have had major problems trying to get Postsharp to work with other technologies e.g. MS Code Analysis and MSBuild.

Upvotes: 1

Domenic
Domenic

Reputation: 112807

Consider an aspect-oriented programming approach, like the one used in this PostSharp example. It would allow you to inject that kind of boilerplate code using attributes.

If you created the appropriate aspect, you could then have code like:

public class A : BaseClass
{
    public event EventHandler OnChanged;

    [ChangedNotify("OnChanged")]
    public bool HasChanged { get; set; }
}

or, if the idea is to have a single OnChange event for multiple properties, you could just hard-code that into the aspect, reducing your code to

public class A : BaseClass
{
    [NotifyOnChanged]
    public bool HasChanged { get; set; }
}

Upvotes: 4

Related Questions