例如这个观察者模式
可以这样写
public abstract aspect ObserverProtocol<S implements Subject, O implements Observer> {
// ...
protected abstract pointcut subjectChange(S s);
protected abstract void updateObserver(S subject, O observer);
}
例如这个观察者模式
可以这样写
public abstract aspect ObserverProtocol<S implements Subject, O implements Observer> {
// ...
protected abstract pointcut subjectChange(S s);
protected abstract void updateObserver(S subject, O observer);
}
是的,通用抽象方面是可能的,请参阅AspectJ 5 Development Kit Developer's Notebook。你会在那里找到一个有启发性的例子。如果您需要更多帮助,请给我一个标志。
更新作为对以下问题的回应:好吧,在这种情况下,我认为在观察者模式中使用泛型没有多大价值,但这是可能的,并且需要一些重构。我克隆了 repo 并稍微重构了代码。现在它看起来像这样(对不起,这会很长!):
package ca.ubc.cs.spl.aspectPatterns.patternLibrary;
import java.util.WeakHashMap;
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
public abstract aspect ObserverProtocol<S extends Subject, O extends Observer> {
private WeakHashMap<S, List<O>> perSubjectObservers =
new WeakHashMap<S, List<O>>();
protected List<O> getObservers(S subject) {
List<O> observers = perSubjectObservers.get(subject);
if (observers == null) {
observers = new LinkedList<O>();
perSubjectObservers.put(subject, observers);
}
return observers;
}
public void addObserver(S subject, O observer) {
getObservers(subject).add(observer);
}
public void removeObserver(S subject, O observer) {
getObservers(subject).remove(observer);
}
protected abstract pointcut subjectChange(S s);
after(S subject): subjectChange(subject) {
Iterator<O> iter = getObservers(subject).iterator();
while (iter.hasNext())
updateObserver(subject, iter.next());
}
protected abstract void updateObserver(S subject, O observer);
}
package ca.ubc.cs.spl.aspectPatterns.patternLibrary;
public interface Subject {}
package ca.ubc.cs.spl.aspectPatterns.patternLibrary;
public interface Observer {}
package ca.ubc.cs.spl.aspectPatterns.examples.observer.aspectj;
import java.awt.Color;
public class Point {
private int x;
private int y;
private Color color;
public Point(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getX() { return x; }
public int getY() { return y; }
public void setX(int x) { this.x = x; }
public void setY(int y) { this.y = y; }
public Color getColor() { return color; }
public void setColor(Color color) { this.color = color; }
}
package ca.ubc.cs.spl.aspectPatterns.examples.observer.aspectj;
public class Screen {
private String name;
public Screen(String s) {
this.name = s;
}
public void display(String s) {
System.out.println(name + ": " + s);
}
}
package ca.ubc.cs.spl.aspectPatterns.examples.observer.aspectj;
import ca.ubc.cs.spl.aspectPatterns.patternLibrary.Subject;
import ca.ubc.cs.spl.aspectPatterns.patternLibrary.Observer;
public aspect SubjectObserverDeclarations {
declare parents: Point implements Subject;
declare parents: Screen implements Observer;
declare parents: Screen implements Subject;
}
package ca.ubc.cs.spl.aspectPatterns.examples.observer.aspectj;
import java.awt.Color;
import ca.ubc.cs.spl.aspectPatterns.patternLibrary.ObserverProtocol;
public aspect ColorObserver extends ObserverProtocol<Point, Screen> {
declare precedence : SubjectObserverDeclarations, ColorObserver;
protected pointcut subjectChange(Point subject):
call(void Point.setColor(Color)) && target(subject);
protected void updateObserver(Point subject, Screen observer) {
observer.display("screen updated (point subject changed color)");
}
}
package ca.ubc.cs.spl.aspectPatterns.examples.observer.aspectj;
import ca.ubc.cs.spl.aspectPatterns.patternLibrary.ObserverProtocol;
public aspect CoordinateObserver extends ObserverProtocol<Point, Screen>{
declare precedence : SubjectObserverDeclarations, CoordinateObserver;
protected pointcut subjectChange(Point subject):
(call(void Point.setX(int)) || call(void Point.setY(int))) && target(subject);
protected void updateObserver(Point subject, Screen observer) {
observer.display("screen updated (point subject changed coordinates)");
}
}
package ca.ubc.cs.spl.aspectPatterns.examples.observer.aspectj;
import ca.ubc.cs.spl.aspectPatterns.patternLibrary.ObserverProtocol;
public aspect ScreenObserver extends ObserverProtocol<Screen, Screen>{
declare precedence : SubjectObserverDeclarations, ScreenObserver;
protected pointcut subjectChange(Screen subject):
call(void Screen.display(String)) && target(subject);
protected void updateObserver(Screen subject, Screen observer) {
observer.display("screen updated (screen subject displayed message)");
}
}
package ca.ubc.cs.spl.aspectPatterns.examples.observer.aspectj;
import java.awt.Color;
public class Main {
public static void main(String argv[]) {
System.out.println("Creating screens s1, s2, s3, s4, s5 and point p");
Point p = new Point(5, 5, Color.blue);
Screen s1 = new Screen("s1");
Screen s2 = new Screen("s2");
Screen s3 = new Screen("s3");
Screen s4 = new Screen("s4");
Screen s5 = new Screen("s5");
System.out.println("Creating observing relationships:");
System.out.println("- s1 and s2 observe color changes to p");
System.out.println("- s3 and s4 observe coordinate changes to p");
System.out.println("- s5 observes s2's and s4's display() method");
ColorObserver.aspectOf().addObserver(p, s1);
ColorObserver.aspectOf().addObserver(p, s2);
CoordinateObserver.aspectOf().addObserver(p, s3);
CoordinateObserver.aspectOf().addObserver(p, s4);
ScreenObserver.aspectOf().addObserver(s2, s5);
ScreenObserver.aspectOf().addObserver(s4, s5);
System.out.println("Changing p's color:");
p.setColor(Color.red);
System.out.println("Changing p's x-coordinate:");
p.setX(4);
System.out.println("done.");
}
}
如您所见,抽象基础方面ObserverProtocol
现在使用泛型,但代价是我们现在需要SubjectObserverDeclarations
为我们的declare parents
语句提供方面,否则派生方面无法使用类,因为如果我们在其中声明父级,则为时已晚派生方面以正确编译(母鸡问题)。
您还看到,因此切入点subjectChange
现在将其目标绑定到具体类,而不是接口Subject
。同样,方法updateObserver
也使用类而不是接口。
为了简单起见,我从基本方面提取了接口Subject
,Observer
以避免像这样的方面声明:
public abstract aspect ObserverProtocol<
S extends ObserverProtocol.Subject,
O extends ObserverProtocol.Observer>
{
//...
}