初学设计模式(1)-----监视者(兽人苦工)

来源:互联网 发布:linux iso文件怎么安装 编辑:程序博客网 时间:2024/06/11 21:14

跟随九天玄女的练级之路并不如想象中的那么轻易,尤其是那些心法,晦涩难懂,更别说应用到实际。但即便这么说,总有一天你会发现,原来自己等级已经那么高了,终于可以开始raid了!!!

开始今天的总结吧。

心法(1):监视者。English name is:Observer. 但其实我更愿叫他,兽人苦工(最爱说的那句,CaoNiMa)。为什么呢,后面我会解释。而现在,我想每位实践者当看到或者发现一个新的设计模式最想知道的一定是,我要为啥要用它,它有啥好的,它能帮助我多少。。。。。。看,这就是实践者的思维,实用大于理论。(怪不得咱大都木有妹子啊。。。。。。)既然如此,那咱就先让它如实招来。监视者(兽人苦工)最大的好处在于,你只需要告诉它,我要采木头,我要采金矿,我要造兵营。。。但是我不需要知道,你怎么采木头,怎么挖金矿,怎么造房子。如此一来,我们的client code就如同一道一道命令,而我们的监视者(兽人苦工)就是执行命令的人,它收到命令,自然会去工作,不用教,不用付钱,任劳任怨。(唉,好人啊。。。囧)

废话到这里,上代码:

AuctionItemObject类,被处理的数据类,可以当作是兽人苦工采集对象

public class AuctionItemObject {private int id;public int getGold() {return gold;}public void setGold(int gold) {AuctionItemObject.gold = gold;}private static int gold;public int getId() {return id;}public void setId(int id) {this.id = id;}}


Subject接口,提供业务处理行为接口,由业务处理层对象实现


public interface Subject {public void registerObserver(Observer observer);public void removeObserver(Observer observer);public void notifyAllObservers();public void notifyObserver(Observer observer);}

TradeDataObject类,业务处理层对象,可以当作是一个在玩魔兽的玩家,或者就是魔兽程序本身

public class TradeDataObject implements Subject {ArrayList<Observer> observerArray = new ArrayList<Observer>();public static ArrayList<AuctionItemObject> auctionItems = new ArrayList<AuctionItemObject>();private AuctionItemObject currentAuctionItem;public AuctionItemObject getCurrentAuctionItem() {return currentAuctionItem;}public AuctionItemObject pullDataFromDatabase(int id){//should be got by id//System.out.println(auctionItems.hashCode());synchronized (auctionItems) {for(AuctionItemObject obj:auctionItems){if(obj.getId()==id){System.out.println("already has an auction item");this.currentAuctionItem=obj;return obj;}}//get from databaseSystem.out.println("create a new auction item");AuctionItemObject newobj=new AuctionItemObject();newobj.setId(id);auctionItems.add(newobj);this.currentAuctionItem=newobj;return newobj;}}public void removeAuctionData(AuctionItemObject obj){if(auctionItems.contains(obj)){auctionItems.remove(obj);}}@Overridepublic void registerObserver(Observer observer) {// TODO Auto-generated method stubif (!observerArray.contains(observer)) {observerArray.add(observer);}}@Overridepublic void removeObserver(Observer observer) {// TODO Auto-generated method stubif (observerArray.contains(observer)) {observerArray.remove(observer);}}@Overridepublic void notifyAllObservers() {// TODO Auto-generated method stubfor(Observer o:observerArray){o.doAction(this);}}@Overridepublic void notifyObserver(Observer observer) {// TODO Auto-generated method stubobserver.doAction(this);}public void bidAndFix(int gold){if(gold<=currentAuctionItem.getGold()){for(Observer obs:observerArray){if(obs instanceof ObserverResponse){System.out.println("Your gold is too little.......");notifyObserver(obs);}}}else{synchronized (currentAuctionItem) {currentAuctionItem.setGold(gold);notifyAllObservers();}}}}

监视者(兽人苦工)

public class ObserverResponse implements Observer {public Subject subject;public ObserverResponse(Subject s){s.registerObserver(this);}@Overridepublic void doAction(Subject subject) {// TODO Auto-generated method stubif (subject instanceof TradeDataObject) {TradeDataObject obj = (TradeDataObject) subject;createResponse(obj.getCurrentAuctionItem());}}private void createResponse(AuctionItemObject auctionItemObject) {// TODO Auto-generated method stubSystem.out.println("Here is the response for "+auctionItemObject.getId());}}

public class ObserverUpdate implements Observer {public Subject subject;public ObserverUpdate(Subject s){s.registerObserver(this);}static int i=0;@Overridepublic void doAction(Subject subject) {// TODO Auto-generated method stubif(subject instanceof TradeDataObject){TradeDataObject obj=(TradeDataObject)subject;AuctionItemObject auction=obj.getCurrentAuctionItem();synchronized (auction) {System.out.println("Now begin to update the datase!");System.out.println("***********");updateDatabase(auction);}}}private void updateDatabase(AuctionItemObject auctionItemObject) {// TODO Auto-generated method stubSystem.out.println("Thread "+(++i)+":Database has been updated!");System.out.println("Now the gold is: "+auctionItemObject.getGold());}}

Main函数

public class Main {static int num=10;public static void main(String[] args) {for (int i = 0; i < 5; i++) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubTradeDataObject obj = new TradeDataObject();obj.pullDataFromDatabase(100);ObserverResponse reponse = new ObserverResponse(obj);ObserverUpdate update = new ObserverUpdate(obj);obj.bidAndFix(getNumber());}});t.start();}}static int getNumber(){return num+=10;}}


代码或许看着有点多,直接把他在eclipse里面跑一遍,便知他在干什么。某些与主题无关的就不提了,比如线程同步等。在Main函数中可以看到,我们起了5个程序(Thread里的),并给每个程序添加了2个监视者,也就是2个兽人苦工,之后给它一条命令(bidAndFix)去做他的事情。那么,此时回到ThadeDataObject类里面可以看到,bidAndFix命令是为了做一个set的操作,当然有其判定条件。但是set仅仅只是更改了TradeDataObject的某个成员变量,就如同只是更改了当前程序中的玩家金币数。可是获取金币难道不应该是让苦工采的么?对,所以我们调用了叫notify的函数,去通知苦工,于是一个苦工去采矿了(response),一个苦工去采木头了(update),至于采集过程中风骚的走位和时不时的抱怨"CaoNiMa"就不是我们玩家关心的了。(或许这里的比喻不恰当,一条命令怎么可能让两个苦工做两件事情呢?其实我们可以把命令抽象看成是一套指令,一套指令会让多个苦工做他们的事情)

所以,在这里,就可以很明显的看出,我们改变了TradeDataObject数据,也就是我们的金币数,怎么更改的?让苦工去做的。怎么让它去做的?通知它的。我们(TradeDataObject)需要知道它怎么做么?不需要。那么,所有细节处理和抽象的业务处理就被彻底剥离,日后你要让苦工又采矿,又造房子,又去A怪,还是探视野,只要创建一个对应的Observer,就可以在需要的地方通知它一下,它就会去做了。于是,我们终于不再喊"CaoNiMa",而是交给他去喊了。

这里,我们就可以引出一条设计原则-----Strive for loosely coupled designs between objects that interact.让创建的每个需要彼此交互的对象低耦合。什么是需要彼此交互的对象?什么又是低耦合呢?很简单,在以上的程序中,交互的对象就是TradeDataObject和两个Observer,但是他们之间的交互仅仅是一个notify,TradeDataObject不知道Observer如何后台处理,而Observer也不知道TradeDataObject如何做逻辑判定,一个只管send notification,一个只管receive notification。以上就是低耦合。

还有一个比较有意思的是,我们传递在notify中传递的参数是this,而不是一个具体的数值,这其实牵涉到两个概念:PullData和SendData。我们的程序中使用的是pull方式,所以会看到在observer中有与之对应的get方法调用。当然,我们也可以使用send方式,直接把gold值传送过去。只是。。。这两种哪种好呢?我想答案很明显。当然,这也取决于个人喜好。

需要提的还有一点是,我们在TradeDataObject中创建了一个observer静态数组,在Observer中创建了TradeDataObject的引用对象。为何?方便添加和删除。也就是说,我们既可以从Observer端注销自己,也可以在TradeDataObject中删除一个Observer。同时,这里也牵涉到另一条设计原则-----Favor composition over inheritance. 组合封装永远优于继承。可见,我么并未通过继承,来实现原本每个observer的操作,因为那么做的话,日后的维护代价会变得很高。怎么高法?想想业务处理对象中的每种操作的增删查改吧。。。

监视者模式到目前为止,个人以为,是一种适合配合数据更改使用的模式。它更适用于那些实时数据并且频繁的更新操作。

最后,我来解释下,为啥我爱叫它兽人苦工呢?因为兽人苦工总是你点它,它才动,你不点,它不动,蜡烛一根,如同代码中的notify。而监视者,个人觉得应该更加智能一点,既然都监视了,那每次的数据改动,它应该会自动执行才是呀,为啥还要notify呢。。。纯属个人观点,如有雷同,他是兽人苦工。。。