/* My example of the Observer Design Pattern */ import java.util.*; //// ideally, the following interfaces and classes should all be made "public" //// and placed in different files. interface observee // also called subject { void attach(investor obv); void detach(investor obv); void notifyobs(); // notify observers } interface observer { void update(stock s); // observee should pass "this" to observer // alternative void update(observee obe) -- requires // type casting: stock s = (stock)obe to obtain stock object. } ////// class stock implements observee { public String symbol; public double price; // probably should be private, but nah ... public double oldprice; // keeps track of changes in price public stock(String s, double p) { symbol=s; price=p; } // constructor public void changeprice(double amt) // +amt for gain, -amt for loss { oldprice = price; price += amt; notifyobs(); // notify investors } ///////// implementation of observee interface ArrayList investors = new ArrayList(); public void attach(investor obv) { investors.add(obv); } public void detach(investor obv) { investors.remove(obv); } public void notifyobs() { for(investor x : investors) { x.update(this); } } } // class stock class investor implements observer // basic investor superclass { public void invest(stock s) { s.attach(this); } public void sellAll(stock s) { s.detach(this); // presumably there will be other data structures to keep track // of how many shares the investor own, etc..., but we'll keep it // simple here. the purpose is to demonstrate the observer pattern. } public void update(stock s) // default to be overridden {} // alternatively, can call this abstract } // superclass investor //////////// concrete observers:: // a bull buys when stocks fall class bullinvestor extends investor implements observer { public void update(stock s) { if (s.price <= s.oldprice) System.out.println("Buy more "+s.symbol+"!"); } } // a bear buys when stocks rise class bearinvestor extends investor implements observer { public void update(stock s) { if (s.price > s.oldprice) System.out.println(" buy "+s.symbol); else System.out.println(" sell all "+s.symbol+"!"); } } ///////////////// public class invest { public static void main(String[] argv) { stock intel = new stock("INTC",12); stock microsoft = new stock("MSFT",24); stock amd = new stock("AMD",7); stock apple = new stock("AAPL",495); investor me = new bearinvestor(); investor you = new bullinvestor(); me.invest(intel); me.invest(apple); you.invest(amd); you.invest(microsoft); intel.changeprice(-1.5); microsoft.changeprice(-0.5); amd.changeprice(+1.0); apple.changeprice(+10); } // main } /* The benefit of the observer pattern is the way that main can now be written. There is on need to maintain any external data structures to keep track of the investments, and no need to have zillions of if-elses to determine the correct behavior of each investor or stock. This program is close to being "fully object oriented". The OOP principle to "let objects decide what to do themselves" is realized. */