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方法是观察者的响应行为。
某一次打印出的结果如下:
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模式会有组合,但我现在还没有学到,就先写这些吧。
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
我自己的理解是:
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();
}
}
}
...{
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模式会有组合,但我现在还没有学到,就先写这些吧。
- Observer模式 学习笔记1
- Observer 模式学习笔记
- Observer模式学习笔记(一)
- Observer模式学习笔记(二)
- 学习笔记----------observer观察者模式
- 设计模式学习笔记--观察者(Observer)模式
- Observer--设计模式学习笔记《二》
- 设计模式学习笔记十九(Observer观察者模式)
- 设计模式学习笔记(七)—Observer观察者模式
- 设计模式学习笔记(二)之观察者模式(Observer)
- java 设计模式学习笔记十三 observer设计者模式
- 【设计模式】学习笔记2:观察者模式(Observer)
- 设计模式学习笔记-观察者模式(Observer)
- 设计模式学习笔记--观察者模式(Observer Pattern)
- 设计模式C++学习笔记之一(Observer观察者模式)
- 设计模式学习笔记——Observer观察者模式
- 设计模式学习笔记——观察者(Observer)模式
- 设计模式 学习笔记 之 观察者模式 Observer (5)
- DataEntry
- Scott Mitchell 的ASP.NET 2.0数据教程之五:: 声明参数
- 感谢CSDN
- 旋转字符输出
- 网络棋牌游戏开发方案整理
- Observer模式 学习笔记1
- 博客第一帖
- TALBES IN SAP(1) -- Customising
- “桥模式”与“极限分割”
- css box model---------it's all about boxes
- hohohoho...^_^
- Linux下Makefile的automake生成全攻略
- linux 下SSH 中文显示乱码解决办法
- TALBES IN SAP(2) -- BASIC DATA / ADMINISTRATION