Skip to content

Instantly share code, notes, and snippets.

@alessandroleite
Created March 6, 2013 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alessandroleite/5099508 to your computer and use it in GitHub Desktop.
Save alessandroleite/5099508 to your computer and use it in GitHub Desktop.
Example of Observer Pattern with AspectJ
package example.types;
import java.util.Arrays;
import example.pattern.Observer;
import example.pattern.Subject;
public class Husband extends Person implements Observer {
private Person wife;
public Husband(String name, Person wife) {
super(name);
this.wife = wife;
wife.attach(this);
}
@Override
public void update(Subject observable, Object... newState) {
System.out.print(observable + " has a new state: ");
Object[] states = (Object[]) newState[0];
for (Object state : states) {
System.out.print(state + " ");
}
System.out.println();
if (Arrays.binarySearch(states, "TPM") > -1 || Arrays.binarySearch(states, "Angry") > -1) {
System.out.println(this.getName() + " pay attention to your own safety!");
}
}
public Person getWife() {
return wife;
}
}
package example.pattern;
public interface Observer {
void update(Subject observable, Object ... newState);
}
package example.aspects;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CopyOnWriteArrayList;
import example.pattern.Observer;
import example.pattern.Subject;
public abstract aspect ObserverPattern {
public abstract pointcut notifyObservers(Subject observable, Object newState);
/*after(Subject observable, Object newState) returning : notifyObservers(observable, newState) {
for (Observer obs : observable.getObservers()) {
obs.update(observable, newState);
}
}*/
Object around(Subject observable, Object newState) : notifyObservers(observable, newState){
Object advicedMethodReturn;
synchronized (thisJoinPoint.getTarget()) {
advicedMethodReturn = proceed(observable, newState);
}
for (Observer obs : observable.getObservers()) {
obs.update(observable, newState, advicedMethodReturn);
}
return advicedMethodReturn;
}
// Subject inter-type declaration
private final Collection<Observer> Subject.observers = new CopyOnWriteArrayList<Observer>();
public void Subject.attach(Observer observer) {
if (observer != null && !observers.contains(observer)) {
observers.add(observer);
}
}
public void Subject.detach(Observer observer) {
if (observer != null) {
observers.remove(observer);
}
}
public Collection<Observer> Subject.getObservers() {
return Collections.unmodifiableCollection(this.observers);
}
}
package example.types;
public class Person {
private String name;
private Object[] emotions = new String[] { "happy" };
public Person(String name) {
this.name = name;
}
public Object[] setEmotions(Object... args) {
Object[] before = this.emotions;
this.emotions = args;
return before;
}
public String getName() {
return name;
}
public Object[] getEmotions() {
return emotions;
}
@Override
public String toString() {
return this.getName();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Person other = (Person) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
}
package example.aspects;
import example.pattern.Subject;
import example.types.Person;
public aspect PersonAspect extends ObserverPattern {
declare parents: Person implements Subject;
public pointcut notifyObservers(Subject observable, Object newState):
target (observable) && (execution (* *.set*(..))) && args(newState);
// pointcut notifyObservers2(Subject observable, Object ... newState):
// target (observable) && (execution (* *.set*(..))) && args(newState);
//
// after(Subject observable, Object[] newState) returning: notifyObservers2(observable, newState) {
// for (Observer obs : observable.getObservers()) {
// obs.update(observable, newState);
// }
// }
}
package example.pattern;
import java.util.Collection;
public interface Subject {
/**
* Add a new {@link Observer} to this observable ({@link Subject}) that will
* be notified when the state of the observable object change.
*
* @param obs
* The {@link Observable} to be add. Must be not
* <code>null</code>.
*/
void attach(Observer obs);
/**
* Remove a given {@link Observer} of this {@link Subject}.
*
* @param obs
* The {@link Observer} to be removed of this {@link Subject}.
*/
void detach(Observer obs);
/**
* Returns a read-only {@link Collection} with the {@link Observer}s of a
* {@link Subject}.
*
* @return A read-only {@link Collection} with the {@link Observer}s of a
* {@link Subject}.
*/
Collection<Observer> getObservers();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment