Message
Gregor
Kiczales wrote:
Yes, the idiom of using:
- an interface to name a role within the
pattern
- having an aspect define advice and
introductions on the interface
- and using declare parents in other
aspects to say what classes play the role in concrete patterns
is the way to go here.
One additional suggestion is to make the
interface, i.e. Singleton, a protected inner interface of the
pattern, i.e. SingletonAspect. That often
makes code like this look better, because it makes it clear
that the interface really only has meaning
withing the aspect (or extensions of the aspect).
Mira Mezini and I had a paper at AOSD'03 that
discussed the pros and cons
of the idiom/pattern mentioned above by
Gregor. In that paper we also make a proposal
on how this and similar idioms can be
expressed more directly with new
programming language constructs. This paper
("Conquering Aspects
Klaus
With Caesar") can be downloaded at http://caesarj.org ..."
With a little additions in the aspectJ language,
it could achieve more power implementing patterns.
I'm talking about adding two new keywords, pertype(TypePattern)
and perinstance(TypePattern).
The pertype keyword associates one aspect instance per class that
match the type pattern. It is ideal for patterns like singleton:
// This is only draft-code
public SingletonAspect pertype(Singleton+)
{
protected interface Singleton {}
private Singleton instance;
pointcut instanceCreation(): initialization(Singleton+.new());
Singleton around(): instanceCreation()
{
if(instance==null)
{
instance=(Singleton)proceed();
}
return instance;
}
}
public aspect MyClassIsASingleton extends SingletonAspect
{
// Make MyClass implements Singleton
declare parents: sample.mypackage.MyClass implements Singleton;
}
As you can see this is pretty more elegant, since you don't need to use
a Map to track the associations of aspects and classes.
This could be done internally at weave time by the aspect compiler (in
fact other implementations, more efficient, not using Maps could be
used).
The perinstance associates an aspect instance per object created whose
class matches the type pattern. It can be used to implements patterns
like subject/observer. Follows draft code for this patter using
perinstance (form an old mail sent to aspect-user).
public abstract aspect SubjectObserverProtocol perinstance(Subject+)
{
protected interface Subject {}
protected interface Observer {}
private Set observers = new HashSet();
public void notifyObservers(Event ev)
{
Iterator it=observers.iterator();
while(it.hasNext())
{
update((Observer)it.next(),ev);
}
}
public void addObserver(Observer o)
{
observers.add(o);
}
// follows point-cuts and advice to capture when is necesary to
// update the subject.
pointcut abstract updateObserver(Subject o,Event e);
protected abstract void update(Observer o,Event ev);
void after(Subject o,Event e) : updateObserver(o,e)
{
// Note the new way of getting an aspect from a particular
object.
o.aspectOf().notifyObservers(e);
}
}
Note that with pertype and perinstance, introductions aren't needed
anymore. I feel that introductions are bad practice since they violate
encapsulation of the target classes and they are not as "transparent"
as we would like. In
http://www.cs.ubc.ca/~jan/AODPs
introductions are avoided too (at least that is my impression).
Indeed the details of these two keywords need more ellaboration (if
community agree with me in adding them to the language).
AspectJ needs improvements in the way it associates aspects with it's
targets (objects/classes/aspects that are affected by the aspect).
Perhaps someones thinks a better way of doing all of this but current
constructions, perthis, pertarget, etc. are not sufficient.
Enrique J. Amodeo Rubio.