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.