当对象间存在一对多关系时,则使用观察者模式。比如当一个对象被修改时,会自动通知它的所有依赖对象,这些依赖对象随之做出相应的反应。观察者模式属于行为型模式。
张六儿喜欢很喜欢玩绝地求生,有时他会带着三个新手朋友一起玩。三个队友由于枪法很差,所以只能躲在张六儿身后躺鸡。队友们时刻关注着右上角的击杀信息,一旦张六儿杀死了敌人,右上角就会弹出一条击杀信息。这时,他的队友们看到张六儿击杀了敌人,就会报以不同的赞美和欢呼。队友一:“66666~”,队友二:“牛逼牛逼!”,队友三:“好厉害!”
我们首先创建一个张六儿类,其中包括一个集合用来存放观察者(队友),一个字符串对象表示击杀敌人的方式,attach方法用来绑定观察者对象,notifyTeamMates方法用来提示队友,相当于系统消息。
public class Zhang6er {
private List<TeamMate> observers = new ArrayList<TeamMate>();
private String kill;
public void setKill(String method) {
this.kill = method;
notifyTeamMates();
}
public String getKill() {
return kill;
}
public void attach(TeamMate teamMate) {
observers.add(teamMate);
}
public void notifyTeamMates() {
System.out.println("系统消息 张六"+this.getKill());
for(TeamMate tm : observers) {
tm.sendMessage();
}
}
}
创建观察者抽象类
public abstract class TeamMate {
protected Zhang6er zhang6er;
public abstract void sendMessage();
}
实现类中,重写构造方法,在构造方法中指定观察的目标并且调用attach()进行绑定
public class Jzp extends TeamMate{
public Jzp(Zhang6er zhang6er) {
this.zhang6er = zhang6er;
zhang6er.attach(this);
System.out.println("Jzp加入了队伍...");
}
@Override
public void sendMessage() {
System.out.println("Jzp:"+this.zhang6er.getKill()+"66666~");
}
}
public class Epilogue extends TeamMate{
public Epilogue(Zhang6er zhang6er) {
this.zhang6er = zhang6er;
zhang6er.attach(this);
System.out.println("Epilogue加入了队伍...");
}
@Override
public void sendMessage() {
System.out.println("Epliogue:"+this.zhang6er.getKill()+"牛逼牛逼!");
}
}
public class Snail extends TeamMate{
public Snail(Zhang6er zhang6er) {
this.zhang6er = zhang6er;
zhang6er.attach(this);
System.out.println("Snail加入了队伍...");
}
@Override
public void sendMessage() {
System.out.println("Snail:"+this.zhang6er.getKill()+"好厉害!");
}
}
主函数
public class Game {
public static void main(String args[]) {
Zhang6er zhang6er = new Zhang6er();
new Jzp(zhang6er);
new Epilogue(zhang6er);
new Snail(zhang6er);
System.out.println("游戏开始了~");
zhang6er.setKill("98k爆头击杀敌人");
zhang6er.setKill("M416击杀敌人");
System.out.println("大吉大利今晚吃鸡~");
}
}
运行结果如下
可以看到每次张六儿击杀敌人,调用setKill方法时,notifyTeamMates()方法同时也被调用,随后程序遍历observers集合中的所有观察者,并依次调用每个观察者对象的sendMessage()方法,于是观察者得到消息,并且做出相应的动作。
优点:
-
观察者和被观察者是抽象耦合的,被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
-
建立了一套触发机制。支持广播通讯,被观察者会向所有的登记过的观察者发出通知。
缺点:
-
如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
-
如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
-
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景:
-
一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
-
一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
-
一个对象必须通知其他对象,而并不知道这些对象是谁。
-
需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
注意事项: 1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。