现在想想,将以前学的一些设计模式搬运到CSDN上来吧,做个备注,防止遗忘。
(1)观察者模式的定义:
指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- 模式的优缺点:
优点:
1、降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
2、目标与观察者之间建立了一套触发机制。
缺点:
1、目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
2、当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
(3)模式的结构图如图1所示。
图1 观察者模式结构图
(4)模式结构
1、抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
2、具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
3、抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
4、具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
图2 数据视图观察者模式实例图
1、Table类是抽象主题角色:提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
2、User类是具体主题角色:实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
3、observer类是抽象观察者角色:是一个接口,包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
4、observer1类和observer2类是具体观察者角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
User类中包含姓名,学号,性别,年龄,成绩等列。
视图1是observer1类,包含姓名、学号、成绩三列。
视图2是observer2类,包含姓名、成绩两列。
更新User类中数据时,两视图也应该作出相应的更新操作。
更新学号,视图1变化,视图2不变化,结果如图3所示。
图3 观察者模式结果-1
更新姓名,视图1变化,视图2也变化,结果如图3所示。
图4 观察者模式结果-2
1.观察者模式主要适用于以下情况:
①当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
②当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要被改变。
③当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,不希望这些对象是紧密耦合的。
2. 观察者模式的优缺点:
观察者模式的主要的作用就是给对象解耦,将观察者和被观察者完全隔离。
①优点
观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。
②缺点
在应用观察者模式时需要考虑一下开发小路问题,程序中包括一个被观察者和多个被观察者,开发和调试比较复杂,而且Java中的消息的通知默认是顺序执行的,一个观察者的卡顿会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。
观察者:Observer接口
package Observer;
public interface observer {
void response(String str,int i,String to);
}
观察者1:
package Observer;
public class observer1 implements observer{
String[][] users = {
{"姓名","学号","成绩"},
{"小A","1704010101","80"},
{"小B","1704010102","100"},
{"小C","1704010103","90"},
{"小D","1704010104","99"},
{"小E","1704010105","70"}
};
@Override
public void response(String str, int i, String to) {
int flag=0;
for(int j=0;j<3;j++){
if(users[0][j].equals(str)==true){
System.out.println("观察者1已更新!");
users[i][j]=to;
flag=1;
}
}
if(flag==0){
System.out.println("观察者1视图无需更新");
}
for(int k=0;k<6;k++){
for(int j=0;j<3;j++){
System.out.printf("%8s\t",users[k][j]);
}
System.out.println();
}
}
}
观察者2:
package Observer;
public class observer2 implements observer {
String[][] users = {
{"姓名","成绩"},
{"小A","80"},
{"小B","100"},
{"小C","90"},
{"小D","99"},
{"小E","70"}
};
@Override
public void response(String str, int i, String to) {
int flag=0;
for(int j=0;j<2;j++){
if(users[0][j].equals(str)==true){
System.out.println("观察者2已更新!");
users[i][j]=to;
flag=1;
}
}
if(flag==0){
System.out.println("观察者2视图无需更新");
}
for(int k=0;k<6;k++){
for(int j=0;j<2;j++){
System.out.printf("%8s\t",users[k][j]);
}
System.out.println();
}
}
}
抽象被观察者:
package Observer;
import java.util.ArrayList;
abstract public class table {
protected ArrayList observers = new ArrayList();
public void push(observer o){
observers.add(o);
}
public void remove(observer o){
observers.remove(o);
}
public abstract void modify(int i,int j,String to);
}
具体被观察者:
package Observer;
public class User extends table {
String[][] users = {
{"姓名","学号","性别","年龄","成绩"},
{"小A","1704010101","男","22","80"},
{"小B","1704010102","男","19","100"},
{"小C","1704010103","男","20","90"},
{"小D","1704010104","男","20","99"},
{"小E","1704010105","男","20","70"}
};
public User(){
for (int i=0;i<6;i++){
for(int j=0;j<5;j++){
System.out.printf("%8s\t",users[i][j]);
}
System.out.println();
}
}
@Override
public void modify(int i,int j,String to) {
String str1 = users[0][j];
for (Object obs:observers){
((observer)obs).response(users[0][j],i,to);
}
}
}
客户端(测试):
package Observer;
import java.util.Scanner;
public class client {
public static void main(String[] args) {
table A711 = new User();
observer obs1 = new observer1();
observer obs2 = new observer2();
A711.push(obs1);
A711.push(obs2);
Scanner cin = new Scanner(System.in);
System.out.println("请输入你要更改的坐标i:1-5 j:0-4 以及你想修改的值:");
while(cin.hasNext()){
int i=cin.nextInt();
int j=cin.nextInt();
String str = cin.next();
A711.modify(i,j,str);
System.out.println("请输入你要更改的坐标i:0-4 j:1-5 以及你想修改的值:");
}
}
}