diff --git a/design-pattern/src/Observer/example03/Application.java b/design-pattern/src/Observer/example03/Application.java new file mode 100644 index 00000000..27363054 --- /dev/null +++ b/design-pattern/src/Observer/example03/Application.java @@ -0,0 +1,22 @@ +package Observer.example03; + +public class Application { + + public static void main(String[] args) { + // 1. 제네릭 + // 2. 델리케이트 + // 3. 내부에 옵저버를 넣는다. + + Button button = new Button(); + button.addObserver(new Observable.Observer() { + @Override + public void update(Observable o, String arg) { + System.out.println(o + " is Clicked"); + } + }); + + button.onClick(); + button.onClick(); + button.onClick(); + } +} diff --git a/design-pattern/src/Observer/example03/Button.java b/design-pattern/src/Observer/example03/Button.java new file mode 100644 index 00000000..90fd69d0 --- /dev/null +++ b/design-pattern/src/Observer/example03/Button.java @@ -0,0 +1,23 @@ +package Observer.example03; + +public class Button { + + private Observable observable; + + public Button() { + observable = new Observable<>(); + } + + public void addObserver(Observable.Observer o) { + observable.addObserver(o); + } + + public void notifyObservers() { + observable.notifyObservers(null); + } + + public void onClick() { + observable.setChanged(); + notifyObservers(); + } +} diff --git a/design-pattern/src/Observer/example03/Observable.java b/design-pattern/src/Observer/example03/Observable.java new file mode 100644 index 00000000..67b596dd --- /dev/null +++ b/design-pattern/src/Observer/example03/Observable.java @@ -0,0 +1,173 @@ +package Observer.example03; + +import java.util.Vector; + +public class Observable { + + private boolean changed = false; + private Vector> obs; + + /** Construct an Observable with zero Observers. */ + + public Observable() { + obs = new Vector<>(); + } + + /** + * Adds an observer to the set of observers for this object, provided + * that it is not the same as some observer already in the set. + * The order in which notifications will be delivered to multiple + * observers is not specified. See the class comment. + * + * @param o an observer to be added. + * @throws NullPointerException if the parameter o is null. + */ + public synchronized void addObserver(Observer o) { + if (o == null) + throw new NullPointerException(); + if (!obs.contains(o)) { + obs.addElement(o); + } + } + + /** + * Deletes an observer from the set of observers of this object. + * Passing {@code null} to this method will have no effect. + * @param o the observer to be deleted. + */ + public synchronized void deleteObserver(Observer o) { + obs.removeElement(o); + } + + /** + * If this object has changed, as indicated by the + * {@code hasChanged} method, then notify all of its observers + * and then call the {@code clearChanged} method to + * indicate that this object has no longer changed. + *

+ * Each observer has its {@code update} method called with two + * arguments: this observable object and {@code null}. In other + * words, this method is equivalent to: + *

{@code + * notifyObservers(null)}
+ * + * @see java.util.Observable#clearChanged() + * @see java.util.Observable#hasChanged() + * @see java.util.Observer#update(java.util.Observable, java.lang.Object) + */ + public void notifyObservers() { + notifyObservers(null); + } + + /** + * If this object has changed, as indicated by the + * {@code hasChanged} method, then notify all of its observers + * and then call the {@code clearChanged} method to indicate + * that this object has no longer changed. + *

+ * Each observer has its {@code update} method called with two + * arguments: this observable object and the {@code arg} argument. + * + * @param arg any object. + * @see java.util.Observable#clearChanged() + * @see java.util.Observable#hasChanged() + * @see java.util.Observer#update(java.util.Observable, java.lang.Object) + */ + public void notifyObservers(T arg) { + /* + * a temporary array buffer, used as a snapshot of the state of + * current Observers. + */ + Vector> arrLocal; + + synchronized (this) { + /* We don't want the Observer doing callbacks into + * arbitrary code while holding its own Monitor. + * The code where we extract each Observable from + * the Vector and store the state of the Observer + * needs synchronization, but notifying observers + * does not (should not). The worst result of any + * potential race-condition here is that: + * 1) a newly-added Observer will miss a + * notification in progress + * 2) a recently unregistered Observer will be + * wrongly notified when it doesn't care + */ + if (!changed) + return; + arrLocal = (Vector>) obs.clone(); + clearChanged(); + } + + for (Observer observer: arrLocal) { + observer.update(this, arg); + } + } + + /** + * Clears the observer list so that this object no longer has any observers. + */ + public synchronized void deleteObservers() { + obs.removeAllElements(); + } + + /** + * Marks this {@code Observable} object as having been changed; the + * {@code hasChanged} method will now return {@code true}. + */ + public synchronized void setChanged() { + changed = true; + } + + /** + * Indicates that this object has no longer changed, or that it has + * already notified all of its observers of its most recent change, + * so that the {@code hasChanged} method will now return {@code false}. + * This method is called automatically by the + * {@code notifyObservers} methods. + * + * @see java.util.Observable#notifyObservers() + * @see java.util.Observable#notifyObservers(java.lang.Object) + */ + protected synchronized void clearChanged() { + changed = false; + } + + /** + * Tests if this object has changed. + * + * @return {@code true} if and only if the {@code setChanged} + * method has been called more recently than the + * {@code clearChanged} method on this object; + * {@code false} otherwise. + * @see java.util.Observable#clearChanged() + * @see java.util.Observable#setChanged() + */ + public synchronized boolean hasChanged() { + return changed; + } + + /** + * Returns the number of observers of this {@code Observable} object. + * + * @return the number of observers of this object. + */ + public synchronized int countObservers() { + return obs.size(); + } + + public interface Observer { + /** + * This method is called whenever the observed object is changed. An + * application calls an {@code Observable} object's + * {@code notifyObservers} method to have all the object's + * observers notified of the change. + * + * @param o the observable object. + * @param arg an argument passed to the {@code notifyObservers} + * method. + */ + void update(Observable o, T arg); + } + +}