Introduction
Probably you've heard of Aspect Oriented Programming (AOP)
, it's a new programming technique that enables you to write code that is easy
to understand, maintain, reuse and evolve.
The current dominant Implementation of the AOP specification is AspectJ(TM)
an extension to the java language that enables developers to express AOP
terminology.
AopDotNetAddIn is a Visual Studio AddIn (attached to this article) that is a
simple implementation of some AOP specifications , and by using this addin you
can write AOP programs using your favorite .NET language ( C#, VB.NET or J#) you
will need not learn any new concepts or constructs to use it.
In this article I'll show you how to use this addin to develop an aspect
oriented implementation of the observer pattern.
Observer Pattern Sample Walkthrough
In this sample we have a simple form SubjectForm that acts as a
subject. and we have also two forms that act as observers
ObserverForm1 and ObserverForm2 the observers will be
interested in observing the change of the BackColor of the
SubjectForm .
In the SubjectForm we have a comboBox with the values Red,
Green, Blue you should choose a color from the list and click the Button
ChangeColor to change the BackColor of the SubjectForm
to the corresponding Color selected in the comboBox.
Public Class SubjectForm
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
.
.
.
#End Region
Public o1 As New ObserverForm1
Public o2 As New ObserverForm2
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim curColor As String = ComboBox1.SelectedItem
Select Case curColor
Case "Red"
Me.BackColor = Color.Red
Case "Green"
Me.BackColor = Color.Green
Case "Blue"
Me.BackColor = Color.Blue
End Select
End Sub
Private Sub SubjectForm_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Me.o1.Location = New Point(Me.Location.X + Me.Width, _
Me.Location.Y + Me.Height)
Me.o1.Show()
Me.o2.Location = New Point(Me.Location.X - Me.Width, _
Me.Location.Y + Me.Height)
Me.o2.Show()
End Sub
End Class
To start coding the pattern let's first write the subject observer protocols.
Public Interface Subject
Sub UpdateObservers()
Sub AddObserver(ByVal ob As Observer)
End Interface
Public Interface Observer
Sub UpdateObserver(ByVal note As Object)
End Interface
Obviously the SubjectForm must implement the
Subject interface and both ObserverForm1 and
ObserverForm2 must implement the Observer interface.
In AOP we separate the Functionality of the Observer Pattern from the classes
participating in this pattern, we will encapsulate this functionality in an
aspect named SubjectObserverAspect .
Choose Project->Add New Item then choose Aspect from the items in the list
(you should see this item after you install the the AopDotNetAddIn), name this
Aspect SubjectObserverAspect .
A class SubjectObserverAspect derived from
AspectLib.Aspect will be added to your project also an xml file
aspectDescriptor.xml will be added
Public Class SubjectObserverAspect
Inherits AspectLib.Aspect
End Class
Coding the Aspect
As we said this aspect will contain the functionality of both the observer
and the subject. Starting with the subject functionality add the following code
to the SubjectObserverAspect aspect
#Region "Subject Functionality"
Public Observers As New ArrayList
Public Sub AddObserver(ByVal ob As Observer)
Observers.Add(ob)
End Sub
Public Sub UpdateObservers(ByVal subj As SubjectForm)
Dim ob As Observer
For Each ob In Observers
ob.Update(subj.BackColor)
Next
End Sub
Public Sub initObservers(ByVal f As SubjectForm)
f.AddObserver(f.o1)
f.AddObserver(f.o2)
End Sub
Public Sub afterEvent(ByVal subj As Subject)
subj.UpdateObservers()
End Sub
#End Region
A subject should have a list of all its observers so we have the
ArrayList Observers, the implementation of the
function AddObserver would add the supplied observer to the
Observers Array. The UpdateObservers function will
loop over all the observers in the Observers array and call the
Update method of each one passing it the background color, note
that we added an argument of type SubjectForm (subj)
to the Update function, this argument enables us to access the
context information we need to know about the Subject (like the background
color).
The initObservers sub is where we register o1 and o2 as
observers of the SubjectForm. The afterEvent sub is
used to start updating the observers. And here is the implementation of the
observer functionality.
#Region "Observer Functionality"
Public Sub UpdateObserver(ByVal obs As Form, ByVal note As Object)
Dim c As Color = CType(note, Color)
obs.BackColor = c
End Sub
#End Region
This implementation will be applied to both ObserverForm1 and
ObserverForm2 which derive from Form so we added an
argument of type Form (obs)
Writing the Weave Instructions (aspectDescriptor.xml)
The weaving the aspect code into the object code (the classes) is determined
by the aspectDescriptor.xml file
="1.0" ="utf-8"
<aspects>
<aspect name="SubjectObserverAspect"
code="SubjectObserverAspect.vb" weave="true">
<advices>
<advice type="after">
<method name="initObservers" />
<pointcut>
<execution>
<method name="SubjectForm_Load"
class="SubjectForm" access="*" return="*"/>
</execution>
</pointcut>
</advice>
<advice type="after">
<method name="afterEvent" />
<pointcut>
<execution>
<method name="Button1_Click"
class="SubjectForm" access="*" return="*" />
</execution>
</pointcut>
</advice>
</advices>
<introductions>
<member name="Observers" introduceto="SubjectForm" />
<interface name="Subject" introduceto="SubjectForm" />
<interface name="Observer" introduceto="Observer*" />
</introductions>
</aspect>
</aspects>
The instructions are defined for each aspect inside the
<aspect> node.
You can introduce new member and/or methods to your classes by specifying
them in the <introductions> node. In our example we specified
that:
- we will add the member
Observers to the
SubjectForm Class.
- the
SubjectForm class will implement the Subject
interface.
- both
ObserverForm1 and ObserverForm2
(Observer*) will implement the Observer interface.
The <advice> node represent pieces of an aspect
implementation to be executed at a point-cut, where the point-cut defines
specific points in a program's execution
The first advice specifies that the initObserves method will be
executed after the SubjectForm_Load method ( which has any access
modifier , any return type and is in the SubjectForm class)
The second advice specifies that the afterEvent method will be
executed after the Button1_Click method ( which has any access
modifier , any return type and is in the SubjectForm class)
Running the Sample
To run this sample choose Build->Weave and Run
Background
Read more about AopDotNetAddIn here.