Wednesday, December 21, 2005

 

Observer Pattern - OO and AO Implementation

參考Aspect-Oriented Design Pattern Implementations
由於版面關係,覺得字體太小請麻煩自行用瀏覽器放大

OOP Implementation

AOP Implementation

  ObserverProtocol.java

import java.util.WeakHashMap;
import java.util.List;
import java.util.LinkedList;

public abstract aspect ObserverProtocol {

   protected interface Subject {}

   protected interface Observer {}

   private WeakHashMap<Subject, List<Observer>> perSubjectObservers;

   protected List<Observer> getObservers(Subject subject) {
      if (perSubjectObservers == null) {
         perSubjectObservers = new WeakHashMap<Subject, List<Observer>>();
      }
      List<Observer> observers = perSubjectObservers.get(subject);
      if (observers == null) {
         observers = new LinkedList<Observer>();
         perSubjectObservers.put(subject, observers);
      }
      return observers;
   }

   public void addObserver(Subject subject, Observer observer) {
      getObservers(subject).add(observer);
   }

   public void removeObserver(Subject subject, Observer observer) {
      getObservers(subject).remove(observer);
   }

   protected abstract pointcut subjectChange(Subject s);

   after(Subject subject): subjectChange(subject) {
      for (Observer o : getObservers(subject)) {
         updateObserver(subject, o);
      }
   }

   protected abstract void updateObserver(Subject subject, Observer observer);
}
Point.java

import java.awt.Color;
import java.util.HashSet;

public class Point implements ChangeSubject {

   private HashSet<ChangeObserver> observers;

   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;
      this.observers = new HashSet<ChangeObserver>();
   }

   public int getX() {
      return x;
   }

   public int getY() {
      return y;
   }

   public void setX(int x) {
      this.x = x;
      notifyObservers();
   }

   public void setY(int y) {
      this.y = y;
      notifyObservers();
   }

   public Color getColor() {
      return color;
   }

   public void setColor(Color color) {
      this.color = color;
      notifyObservers();
   }

   public void addObserver(ChangeObserver o) {
      this.observers.add(o);
   }

   public void removeObserver(ChangeObserver o) {
      this.observers.remove(o);
   }

   public void notifyObservers() {
      for (ChangeObserver o : observers) {
         o.refresh(this);
      }
   }
}
Point.java

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;
   }
}
Screen.java

import java.util.HashSet;

public class Screen implements ChangeSubject, ChangeObserver {

   private HashSet<ChangeObserver> observers;

   private String name;

   public Screen(String s) {
      this.name = s;
      observers = new HashSet<ChangeObserver>();
   }

   public void display(String s) {
      System.out.println(name + ": " + s);
      notifyObservers();
   }

   public void addObserver(ChangeObserver o) {
      this.observers.add(o);
   }

   public void removeObserver(ChangeObserver o) {
      this.observers.remove(o);
   }

   public void notifyObservers() {
      for (ChangeObserver o : observers) {
         o.refresh(this);
      }
   }

   public void refresh(ChangeSubject s) {
      String subjectTypeName = s.getClass().getName();
      subjectTypeName = subjectTypeName.substring(subjectTypeName
            .lastIndexOf(".") + 1, subjectTypeName.length());
      display("update received from a " + subjectTypeName + " object");
   }
}
Screen.java

public class Screen {

   private String name;

   public Screen(String s) {
      this.name = s;
   }

   public void display(String s) {
      System.out.println(name + ": " + s);
   }
}
ChangeSubject.java

public interface ChangeSubject {

   public void addObserver(ChangeObserver o);

   public void removeObserver(ChangeObserver o);

   public void notifyObservers();
}
CoordinateObserver.java

public aspect CoordinateObserver extends ObserverProtocol {

   declare parents: Point  implements Subject;

   declare parents: Screen implements Observer;

   protected pointcut subjectChange(Subject subject): 
      (call(void Point.setX(int)) ||
       call(void Point.setY(int)) ) && target(subject);

   protected void updateObserver(Subject subject, Observer observer) {
      ((Screen) observer)
            .display("Screen updated (point subject changed coordinates).");
   }
}
ChangeObserver.java

public interface ChangeObserver {

   public void refresh(ChangeSubject s);
}
ColorObserver

import java.awt.Color;

public aspect ColorObserver extends ObserverProtocol {

   declare parents: Point  implements Subject;

   declare parents: Screen implements Observer;

   protected pointcut subjectChange(Subject subject): 
      call(void Point.setColor(Color)) && target(subject);

   protected void updateObserver(Subject subject, Observer observer) {
      ((Screen) observer)
            .display("Screen updated (point subject changed color).");
   }
}
  ScreenObserver.java

public aspect ScreenObserver extends ObserverProtocol {

   declare parents: Screen implements Subject;

   declare parents: Screen implements Observer;

   protected pointcut subjectChange(Subject subject): 
      call(void Screen.display(String)) && target(subject);

   protected void updateObserver(Subject subject, Observer observer) {
      ((Screen) observer)
            .display("Screen updated (screen subject displayed message).");
   }
}
Main.java

import java.awt.Color;

public class Main {

   public static void main(String argv[]) {
      // Creating Screen s1,s2,s3,s4,s5 and Point p
      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");
      Point p = new Point(5, 5, Color.blue);

      // s1 and s2 observe color changes to p
      p.addObserver(s1);
      p.addObserver(s2);

      // s3 and s4 observe coordinate changes to p
      p.addObserver(s3);
      p.addObserver(s4);

      // s5 observes s2's and s4's display() method
      s2.addObserver(s5);
      s4.addObserver(s5);

      System.out.println("Changing p's color:");
      p.setColor(Color.red);

      System.out.println("Changing p's x-coordinate:");
      p.setX(4);
   }
}
Main.java

import java.awt.Color;

public class Main {

   public static void main(String argv[]) {
      // Creating Screen s1,s2,s3,s4,s5 and Point p
      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");
      Point p = new Point(5, 5, Color.blue);

      // s1 and s2 observe color changes to p
      ColorObserver.aspectOf().addObserver(p, s1);
      ColorObserver.aspectOf().addObserver(p, s2);

      // s3 and s4 observe coordinate changes to p
      CoordinateObserver.aspectOf().addObserver(p, s3);
      CoordinateObserver.aspectOf().addObserver(p, s4);

      // s5 observes s2's and s4's display() method
      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);
   }
}
Output
Changing p's color:
s1: update received from a Point object
s2: update received from a Point object
s5: update received from a Screen object
s3: update received from a Point object
s4: update received from a Point object
s5: update received from a Screen object
Changing p's x-coordinate:
s1: update received from a Point object
s2: update received from a Point object
s5: update received from a Screen object
s3: update received from a Point object
s4: update received from a Point object
s5: update received from a Screen object
Output
Changing p's color:
s1: Screen updated (point subject changed color).
s2: Screen updated (point subject changed color).
s5: Screen updated (screen subject displayed message).
Changing p's x-coordinate:
s3: Screen updated (point subject changed coordinates).
s4: Screen updated (point subject changed coordinates).
s5: Screen updated (screen subject displayed message).
Problem
  • design pattern侵入原本的程式,將之複雜化
  • 如果要將observer再加以功能區分,程式將會更複雜
Improvement
  • 更好的模組化
  • 容易擴充、縮減

Comments: Post a Comment



<< Home