有可能产生一般方面吗?

时间:2013-04-11 16:45:41

标签: generics aspectj

例如这个观察者模式

https://github.com/eclipse/org.aspectj/blob/master/docs/sandbox/ubc-design-patterns/src/ca/ubc/cs/spl/aspectPatterns/patternLibrary/ObserverProtocol.java

可以像这样编写

public abstract aspect ObserverProtocol<S implements Subject, O implements Observer> {
  // ...
  protected abstract pointcut subjectChange(S s);
  protected abstract void updateObserver(S subject, O observer);
}

1 个答案:

答案 0 :(得分:1)

是的,通用抽象方面是可能的,请参阅AspectJ 5 Development Kit Developer's Notebook。你会在那里找到一个有益的例子。如果您需要更多帮助,请给我一个标志。


更新作为对下面问题的反应:在这种情况下,我认为使用泛型对Observer模式没有多大价值,但这是可能的,需要进行一些重构。我克隆了回购并重新编写了一些代码。现在看起来像这样(对不起,这将是漫长的!):

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,否则派生方面不能使用这些类是因为如果我们在其中声明了父类,那么派生方面的编译就会为时已晚(hen-and-egg问题)。

您还看到,因此切入点subjectChange现在将其目标绑定到具体类,而不再绑定到接口Subject。同样,方法updateObserver也使用类而不是接口。

为简单起见,我从基本方面提取了接口SubjectObserver,以避免方面声明,如:

public abstract aspect ObserverProtocol<
    S extends ObserverProtocol.Subject,
    O extends ObserverProtocol.Observer>
{
    //...
}