Observerobserver=personList.get(i);
observer.hearTelephone(mess);}
changed=false;
}
}
publicvoidgiveNewMess(Stringstr){
if(str.equals(mess))
changed=false;
else{
mess=str;
changed=true;
}
}
}
具体主题通过实现notifyObservers()方法来通知具体观察者,实现的方式是遍历具体主题中用来存放观察者引用的集合,并让集合中的每个具体观察者执行观察者接口规定更新数据的方法。
4.具体观察者_1UniversityStudent.java
publicclassUniverStudentimplementsObserver{
Subjectsubject;
FilemyFile;
UniverStudent(Subjectsubject,StringfileName){
this.subject=subject;
subject.addObserver(this);
myFile=newFile(fileName);
}
publicvoidhearTelephone(StringheardMess){
try{RandomAccessFileout=newRandomAccessFile(myFile,"rw");
out.seek(out.length());
byte[]b=heardMess.getBytes();
out.write(b);
System.out.print("我是一个大学生,");
System.out.println("我向文件"+myFile.getName()+"写入如下内容:
");
System.out.println(heardMess);
}
catch(IOExceptionexp){System.out.println(exp.toString());}
}
}
4.具体观察者_2HaiGui.java
publicclassHaiGuiimplementsObserver{
Subjectsubject;
FilemyFile;
HaiGui(Subjectsubject,StringfileName){
this.subject=subject;
subject.addObserver(this);
myFile=newFile(fileName);
}
publicvoidhearTelephone(StringheardMess){
try{booleanboo=heardMess.contains("java程序员");
if(boo){
RandomAccessFileout=newRandomAccessFile(myFile,"rw");
out.seek(out.length());
byte[]b=heardMess.getBytes();
out.write(b);
System.out.print("我是一个海归,");
System.out.println("我向文件"+myFile.getName()+"写入如下内容:
");
System.out.println(heardMess);
}
else{
System.out.println("我是海归,这次的信息中没有我需要的信息");}
}
catch(IOExceptionexp){System.out.println(exp.toString());}
}
}
5.应用Application.java
publicclassApplication{
publicstaticvoidmain(Stringargs[]){
SeekJobCentercenter=newSeekJobCenter();
UniverStudentzhangLin=newUniverStudent(center,"A.txt");
HaiGuiwangHao=newHaiGui(center,"B.txt");
center.giveNewMess("腾辉公司需要10个java程序员。
");
center.notifyObservers();
center.giveNewMess("海景公司需要8个动画设计师。
");
center.notifyObservers();
center.giveNewMess("仁海公司需要9个电工。
");
center.notifyObservers();
center.giveNewMess("仁海公司需要9个电工。
");
center.notifyObservers();
}
三、“推”数据与“拉”数据
•推数据方式是指具体主题将变化后的数据全部交给具体观察者。
–具体主题认为具体观察者需要这些变化后的全部数据
•拉数据方式是指具体主体提供了获得变化后数据的方法,具体观察者调用这些方法获得变化后的数据。
–具体主题不知道具体观察者是否需要这些变化后的数据行为协作
四、观察者模式的优点
•具体主题和具体观察者是松耦合关系。
由于主题(Subject)接口仅仅依赖于观察者(Observer)接口,因此具体主题只是知道它的观察者是实现观察者(Observer)接口的某个类的实例,但不需要知道具体是哪个类。
同样,由于观察者仅仅依赖于主题(Subject)接口,因此具体观察者只是知道它依赖的主题是实现主题(subject)接口的某个类的实例,但不需要知道具体是哪个类。
•观察模式满足“开-闭原则”。
主题(Subject)接口仅仅依赖于观察者(Observer)接口,这样,我们就可以让创建具体主题的类也仅仅是依赖于观察者(Observer)接口,因此如果增加新的实现观察者(Observer)接口的类,不必修改创建具体主题的类的代码。
同样,创建具体观察者的类仅仅依赖于主题(Observer)接口,如果增加新的实现主题(Subject)接口的类,也不必修改创建具体观察者类的代码。
五、应用举例
•老师有电话号码,学生需要知道老师的电话号码以便于在合时的时候拨打,在这样的组合中,老师就是一个被观察者(Subject),学生就是需要知道信息的观察者,当老师的电话号码发生改变时,学生得到通知,并更新相应的电话记录
publicinterfaceSubject{
publicvoidattach(Observero);
publicvoiddetach(Observero);
publicvoidnotice();
}
packageobserver;
publicinterfaceObserver{
publicvoidupdate();
}
publicclassTeacherimplementsSubject{
privateStringphone;
privateVectorstudents;
publicTeacher(){
phone="";
students=newVector();
}
publicvoidattach(Observero){
students.add(o);
}
publicvoiddetach(Observero){
students.remove(o);
}
publicvoidnotice(){
for(inti=0;i((Observer)students.get(i)).update();
}
publicvoidsetPhone(Stringphone){
this.phone=phone;
notice();
}
publicStringgetPhone(){
returnphone;
}
}
publicclassStudentimplementsObserver{
privateStringname;
privateStringphone;
privateTeacherteacher;
publicStudent(Stringname,Teachert){
this.name=name;
teacher=t;
}
publicvoidshow(){
System.out.println("Name:
"+name+"\nTeacher'sphone:
"+phone);
}
publicvoidupdate(){
phone=teacher.getPhone();
}
}
publicclassClient{
publicstaticvoidmain(String[]args){
Vectorstudents=newVector();
Teachert=newTeacher();
for(inti=0;i<10;i++){
Studentst=newStudent("lili"+i,t);
students.add(st);
t.attach(st);
}
t.setPhone("");
for(inti=0;i<10;i++)
((Student)students.get(i)).show();
t.setPhone("");
for(inti=0;i<10;i++)
((Student)students.get(i)).show();
}
}
第七章策略模式
策略模式(别名:
政策)
定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。
本模式使得算法可独立于使用它的客户而变化。
StrategyPattern(AnotherName:
Policy)
Defineafamilyofalgorithms,encapsulateeachone,andmaketheminterchangeable.Strategyletsthealgorithmvaryindependentlyfromclientsthatuseit.
一、概述
策略模式是处理算法的不同变体的一种成熟模式,策略模式通过接口或抽象类封装算法的标识,即在接口中定义一个抽象方法,实现该接口的类将实现接口中的抽象方法。
在策略模式中,封装算法标识的接口称作策略,实现该接口的类称作具体
二、策略模式的结构与使用
策略模式的结构中包括三种角色:
•策略(Strategy)
•具体策略(ConcreteStrategy)
•上下文(Context)
•策略模式的UML类图
策略模式的结构的描述与使用
在某种比赛中有若干个裁判,每位裁判给选手一个得分。
选手的最后得分是根据全体裁判的得分计算出来的。
请给出几种计算选手得分的评分方案,对于某次比赛,可以从你的方案中选择一种方案作为本次比赛的评分方案。
•1.策略(Strategy):
Computable.java
publicinterfaceComputableStrategy{
publicabstractdoublecomputeScore(double[]a);
}
2.具体策略(ConcreteStrategy):
StrategyOne.java
(代数平均值方法)
publicclassStrategyOneimplementsComputableStrategy{
publicdoublecomputeScore(double[]a){
doublescore=0,sum=0;
for(inti=0;isum=sum+a[i];
}
score=sum/a.length;
returnscore;
}
}
2.具体策略(ConcreteStrategy):
StrategyTwo.java
(去掉最大值和最小值,然后计算代数平均值)
importjava.util.Arrays;
publicclassStrategyTwoimplementsComputableStrategy{
publicdoublecomputeScore(double[]a){
if(a.length<=2)
return0;
doublescore=0,sum=0;
Arrays.sort(a);
for(inti=1;isum=sum+a[i];
}
score=sum/(a.length-2);
returnscore;
}
}
3.上下文:
GymnasticsGame.java
publicclassGymnasticsGame{
ComputableStrategystrategy;
publicvoidsetStrategy(ComputableStrategystrategy){
this.strategy=strategy;
}
publicdoublegetPersonScore(double[]a){
if(strategy!
=null)
returnputeScore(a);
else
return0;
}
}
4.应用:
Application.java_1
publicclassApplication{
publicstaticvoidmain(Stringargs[]){
GymnasticsGamegame=newGymnasticsGame();
game.setStrategy(newStrategyOne());
Personzhang=newPerson();
zhang.setName("张三");
double[]a={9.12,9.25,8.87,9.99,6.99,7.88};
Personli=newPerson();
li.setName("李四");
double[]b={9.15,9.26,8.97,9.89,6.97,7.89};
zhang.setScore(game.getPersonScore(a));
li.setScore(game.getPersonScore(b));
System.out.println("使用算术平均值方案:
");
System.out.println("得分:
",zhang.getName(),zhang.getScore());
System.out.println("得分:
%5.3f%n",li.getName(),li.getScore());
}
}
4.应用:
Application.java_2
classPerson{
Stringname;
doublescore;
publicvoidsetScore(doublet){
score=t;
}
publicvoidsetName(Strings){
name=s;
}
publicdoublegetScore(){
returnscore;
}
publicStringgetName(){
returnname;
}
}
三、策略模式的优点
•上下文(Context)和具体策略(ConcreteStrategy)是松耦合关系。
因此上下文只知道它要使用某一个实现Strategy接口类的实例,但不需要知道具体是哪一个类。
•策略模式满足“开-闭原则”。
当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例。
四、适合使用策略模式的情景
•一个类定义了多种行为,并且这些行为在这个类中以多个条件语句的形式出现,可以使用策略模式避免在类中使用大量的条件语句。
•程序不需要暴露复杂的、与算法相关的数据结构,可以使用策略模式封装算法。
•需要使用一个算法的不同变体。
•把数组导出为表格的算法,输入一个数组,导出一个表格,当用户想改变导出的表格时,便可以通过改变输出的算法改变输出的结果。
如果输出的内容用以网页显示,则输出
•如果输出的结果用以直接的屏幕输出,则可以输出:
+----+----+-----+------+
|Jack|Maya|Mikes|Shadow|
+----+----+-----+------+
publicinterfaceTableExporter{
publicStringgetExported(String[]data);
}
publicclassHtmlExporterimplementsTableExporter{
publicStringgetExported(String[]data){
if(data==null){
return"";
}
StringBuffersb=newStringBuffer();
sb.append("
");for(inti=0;isb.append("
"+data[i]+" |
");
sb.append("
");
returnsb.toString();
}
}
publicclassLineExporterimplementsTableExporter{
publicStringgetExported(String[]data){
if(data==null){
return"";
}
StringBuffertop=newStringBuffer("+");
StringBuffermid=newStringBuffer("|");
for(inti=0;iStringstr=data[i];
for(intj=0;jtop.append("-");
mid.append(str);
top.append("+");
mid.append("|");
}
top.append("\n");
mid.append("\n");
returntop.toString()+mid.toString()+top.toString();
}
}
publicclassClie