Observer模式 学习笔记1

来源:互联网 发布:日系女装品牌 知乎 编辑:程序博客网 时间:2024/05/15 23:49
        GOF的设计模式中是这样描述Observer模式的意图(intent)的:
        定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

        我自己的理解是:
        Observer模式定义了一种多个对象之间的一对多的相互依赖关系,当一个对象的状态发生改变时,其他与之有关系的对象“看上去”都要相应采取行动。


试着用Observer模式写了一些代码,模拟灌篮比赛,运动员每次灌完之后,评委为他们打分。
在这里Player是Subject;
ChinesePlayer和USPlayer是ConcreteSubject;
Rater是Observer
DunkRater是ConcreteObserver

Player中的endPlaying方法就是Player的行为或(引起观察者行为的)事件。
Rater中的rate方法是观察者的响应行为。           

//全部折叠

public abstract class Player
{
    
protected String name;
    
protected int height;
    
public String getPlayerName()
    
{
        
return this.name;
    }

    
    
public int getPlayerHeight()
    
{
        
return this.height;
    }

    
private ArrayList<Rater> raterList = new ArrayList<Rater>();
    
    
public void addRater(Rater rater)
    
{
        
this.raterList.add(rater);
    }

    
    
public void removeRater(Rater rater)
    
{
        
this.raterList.remove(rater);
    }

    
    
protected void askForRating()
    
{
        
for(Rater rater : this.raterList)
        
{
            rater.rate();
        }

    }

    
    
/*
    这里不写成dunk()是为了以后的扩展之用,因为可能现在开发的是灌篮比赛,
    以后再加入其他类型的比赛,比如投篮。
    可以采用策略模式来完成。
    
*/

    
public void play()    
    
{    
        
//some code to describe play
    }

    
    
public void endPlaying()
    
{
        askForRating();
    }

}


public class USPlayer extends Player
{
    
public USPlayer(String name)
    
{
        
this.name = name;
    }

    
    
public void play()
    
{
        System.out.println(
this.name + " have a highflyer dunk"); 
    }

}


public class ChinesePlayer extends Player
{
    
public ChinesePlayer(String name)
    
{
        
this.name = name;
    }

    
    
public void play()
    
{
        System.out.println(
this.name + " have a power dunk"); 
    }

}


public abstract class Rater
{
    
protected String name;
    
public abstract void rate();
}


public class DunkRater extends Rater
{

    
public DunkRater(String name)
    
{
        
this.name = name;
    }

    
    
public void rate()
    
{
        
// TODO 自动生成方法存根
        int score = (int)(Math.random() * 8+ 2;
        System.out.println(
this.name + "" + score);
    }


}


public class DunkGame
{
    
public static void main(String[] args)
    
{
        Rater rater1 
= new DunkRater("Kobe");
        Rater rater2 
= new DunkRater("Jordan");
    
        Player player1 
= new ChinesePlayer("Yao Ming");
        Player player2 
= new USPlayer("James");
        
        player1.addRater(rater1);
        player1.addRater(rater2);
    
        player2.addRater(rater1);
        player2.addRater(rater2);
        
        player1.play();
        player1.endPlaying();
        
        player2.play();
        player2.endPlaying();
    }

    
}

}


某一次打印出的结果如下:
Yao Ming have a power dunk
Kobe: 4
Jordan: 4
James have a highflyer dunk
Kobe: 7
Jordan: 5

  
 几点讨论:

1)在Player(Subject)中的那个raterList是否可以把private改为protected?
   我觉得改了不好,因为不应该把“用什么数据结构、何种方式保存Rater(Observer)”暴露给用户。(客户程序员,他们可以扩展Player这个抽象类),否则就违背了封装性。

2)从面向对象的几个原则来看Observer模式
    a)把变化的部分封装起来:
       我们可以很好地扩展Player和Rater两个部分,彼此没有过多影响。因此Observer模式在方面做的还是很好的。
      ConcretePlayer与ConcreteRater这间的联系就是ConcretePlayer维护着一个注册过的现有的Rater(Observer)的列表(这个列表的实现方式对于负责扩展地程序员应该是透明的),ConcretePlayer不知道它的监听者具体是什么类型,只知道它们实现了Rater(Observer)的接口。
       

    b)面向接口编程而不是面向实现
      在客户主程序中,只出现了三个具体的类,这样的问题可以通过工厂模式解决。
      值得注意的一点,也是Head First in Design Patterns中对于这条原则的一个解释:
      一直以来我们所说的面向对象设计中很重要的一条原则--面向接口编程,再加之继承存在的种种问题,容易使人产生错觉:使用关键字interface。
      实际上这条原则的一个等价的说法是“面向SuperType编程”。这里的SuperType的意思是接口或者超类。
      因此用abstract class并没有违反这样的原则,反而是遵守了。

3)语义上与实现上是否是相反的
   我不明白是翻译问题还是我自己没懂,总觉得GOF的描述中“自动”二字和“观察者”会给读者带来误解。
   原因如下:
        Observer模式描述的是这样的一种情况:
        当一个Subject的状态发生变化或被触发了一个事件的时候,在这个Subject上注册的对象要依据这样的变化或事件做出相应的反映,这些对象然后被称之为Observers。
        按照GOF的说法,从语义上来说应该是Observer主动响应了这个行为。
        但在实现上应该是Subject调用Observer的这个响应行为,这就是我上面所说的“看上去”主动响应,实际上是被动地被Subject调用。
        因此Observer和自动不免给人带来误解,站在Subject的角度上给这个模式取名,叫作通知者模式也许更好。
        
        
        这个例子,以后会重构,将其他模式应用上去。在网上学习的过程中,知道Observer模式和责任链模式、MVC模式会有组合,但我现在还没有学到,就先写这些吧。
        

       


      
  
 



        
       
         
 

原创粉丝点击