Property Event Pattern
Introduction
Since the advent of .NET, one of my most frequent and useful patterns is using an event to notify change in state. Applying this pattern has reduced overall code, improved reliability, and made maintenance and expansion easier.
Why? The Context
Without events, spaghetti code occurs real quickly when one method changes state that other code is dependant on without notifying that the change is made. This is one of the most frequent causes of coding errors (bugs) in mid-to-large applications that I have seen. Events go a long way in solve this issue.
This should be obvious with public properties that can be changed externally, but must be acted upon by the owner. Such as the Text property on a label, when changed, the label must be redrawn.
Common Example
This is used extensively on Windows Forms components. Almost every property has an associated change event. TextChanged for the Text property, EnableChanged for the Enabled property and so on.
Internally Critical
This pattern becomes more subtle but critical with internal members. In larger applications, for clarity, I wrap most all class variables in properties with change events. If the class is designed to be inherited, this becomes all the more important as you can not rely on derived classes to notify your code when they change state.
The Solution
- Subscribe to Events
Code that depends on a class' state can subscribe to the appropriate change event to receive notification of when that state changes to take appropriate action.
- Event Triggers
The "Event Triggers" allow easy triggering of the event and allow derived classes the option of first notification (before the event occurs).
- Internal Access Through Properties
Even internal members should access the variable through the property to ensure that notification occurs. In other words, members should not access the class variable directly, only through the property.
#region Public Events
public event EventHandler DevicePortChanged;
#endregion
#region Property Variables
private int m_DevicePort;
#endregion
#region Public Properties
public int DevicePort
{
get {return m_DevicePort;}
set
{
int saved = m_DevicePort;
m_DevicePort = value;
if (saved != value) OnDevicePortChanged(EventArgs.Empty);
}
}
#endregion
#region Event Triggers
protected virtual void OnDevicePortChanged(EventArgs e)
{ if (DevicePortChanged != null) DevicePortChanged(this, e); }
#endregion
|
References