java 观察者模式_Java之观察者模式(Observer)

1. 设计意图

定义对象之间的一对多依赖关系,以便当一个对象更改状态时,将自动通知和更新其所有依赖项。

8fa57f19836b0a5105760961610e9b65.png

简而言之

你别来找我,给我你的联系方式,有事我会主动联系你

2.案例演示

以当前最火热的吃鸡游戏作为一个简单的案例来演示观察者模式,当玩家进入游戏时,会收到游戏服务器推送的提示消息,随着游戏的进行,如果某个玩家被Kill掉了,游戏服务器会把此消息推送给房间里的其他玩家。在本案例中,“游戏” 是一个抽象的被观察者,“吃鸡游戏” 是具体的被观察者;“游戏玩家”是一个抽象的观察者(接口),而玩家A、玩家B等是具体的观察者。案例的UML关系如下图:

191978f3f35459b50a558783dd41106f.png

3. 示例代码

3.1 抽象的被观察者类(Subject)

AbstractGame.java

package com.ramostear.pattern.observer;import java.util.ArrayList;/** * @author ramostear * @create-time 2019/1/5 0005-23:27 * @modify by : * @info:[抽象的被观测者类] * @since: */public abstract class AbstractGame { /** * 定义一个存放观察者的容器 */ public final ArrayList obsList = new ArrayList<>(); /** * 注册观察者 * @param obs 观察者 * @param  */ public  void attach(Observer obs){ if (obs == null){ throw new NullPointerException("Observer is null."); }else{ this.attachObs(obs); } } /** * 注册观察者 * @param obs */ private void attachObs(Observer obs){ if (obs == null){ throw new NullPointerException("class is null"); }else { synchronized (obsList){ if(!obsList.contains(obs)){ obsList.add(obs); } } } } /** * 注销观察者 * @param obs 观察者 * @param  */ public  void detach(Observer obs){ if(obs == null){ throw new NullPointerException("Observer is null"); }else { this.detachObs(obs); } } /** * 注销观察者 * @param obs */ private void detachObs(Observer obs){ if(obs == null){ throw new NullPointerException("Class is null"); }else{ synchronized (obsList){ obsList.remove(obs); } } } /** * 通知所有的观察者 * @param messages */ public abstract void notifyAllObs(String...messages); /** * 通知某个观察者 * @param obs * @param messages */ public abstract void notifyObs(Observer obs,String...messages);}

AbstractGame类中定义了添加、删除和通知观察者的方法,同时有一个List类型的容器,用于保存已注册的观察者,当需要通知观察者时,从容器中取出观察者信息。

说明:抽象的被观察者可以定义成一个抽象类或者接口,本案例中采用的是抽象类

3.2 抽象的观察者接口(Observer)

Observer.java

package com.ramostear.pattern.observer;/** * @author ramostear * @create-time 2019/1/5 0005-23:26 * @modify by : * @info:[观察者接口] * @since: */public interface Observer { /** * 更新状态 * @param messages */ void update(String... messages);}

在该接口中定义了一个update() 方法,当被观察者发出通知时,此方法会被调用。

3.3 具体被观察者(ConcreteSubject)

ChikenGame继承了AbstractGame类,并对通知方法进行了具体的实现。

ChikenGame.java

package com.ramostear.pattern.observer;/** * @author ramostear * @create-time 2019/1/5 0005-23:55 * @modify by : * @info:[吃鸡游戏类] * @since: */public class ChickenGame extends AbstractGame { private String roomName; public ChickenGame(String roomName) { this.roomName = roomName; } public String getRoomName() { return roomName; } public void setRoomName(String roomName) { this.roomName = roomName; } @Override public void notifyAllObs(String... messages) { obsList.forEach(obs->{ this.notifyObs(obs,messages); }); } @Override public void notifyObs(Observer obs, String... messages) { if (obs == null){ throw new NullPointerException("Observer is null"); }else{ obs.update(messages); } }}

3.4 具体观察者(ConcreteObserver)

Gamer类实现了Observer接口,并对Observer的update方法进行了具体的实现;这里为了演示,只是简单的对消息进行输出。

Gamer.java

package com.ramostear.pattern.observer;/** * @author ramostear * @create-time 2019/1/6 0006-0:06 * @modify by : * @info:[游戏玩家] * @since: */public class Gamer implements Observer{ private String name; public Gamer(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public void update(String... messages) { System.out.println("玩家:"+name); for (String message:messages){ System.out.println("消息->"+message+""); } }}

3.5 测试本次案例

创建一个吃鸡游戏叫“三国吃鸡演义” ,将刘、关、张三个玩家注册到吃鸡游戏中。游戏发布消息给三个玩家,刘、关、张同时收到游戏发出的消息,当关羽挂掉后,只有刘、张两个玩家收到消息;当张飞再挂掉后,只有刘备收到消息。为了演示观察者模式,最后我们让关羽满血复活,此时刘、关二人收到游戏发出的消息。

App.java

package com.ramostear.pattern.observer;/** * @author ramostear * @create-time 2019/1/6 0006-0:08 * @modify by : * @info:[测试类] * @since: */public class App { public static void main(String[] args){ ChickenGame game = new ChickenGame("三国吃鸡演义"); Gamer gamerLiu = new Gamer("刘备"); Gamer gamerZhang = new Gamer("张飞"); Gamer gamerGuan = new Gamer("关羽"); game.attach(gamerLiu); game.attach(gamerGuan); game.attach(gamerZhang); game.notifyAllObs("欢迎进入"+game.getRoomName()); game.notifyAllObs(new String[]{"刘关张桃园三结义,开始三国吃鸡演义..."}); game.detach(gamerGuan); game.notifyAllObs("#关羽:"我去!被98K爆了,快来扶我一下!""); game.notifyAllObs("#刘备:"我去,这货肥得一批!""); game.detach(gamerZhang); game.notifyAllObs("#张飞:"我去,这比是挂!""); game.notifyAllObs("#刘备:"我去!咋这么多人,我凉了!""); game.attach(gamerGuan); game.notifyAllObs("关羽满血复活"); game.notifyAllObs("#刘备:"苟住,苟住就能赢!""); }}

测试结果:

dc70fbfedefacddb772a8809558f8036.png

4. 适用性

当满足以下情况中的一种时使用观察者模式

  • 当抽象有两个Aspect时,一个依赖于另一个。 将这些Aspact封装在单独的对象中可让您独立地改变和重用它们.
  • 当一个对象的更改需要更改其他对象时,你不知道到底需要更改多少个关联的对象
  • 当不希望多个对象之前发生紧耦合时

5. 真实案例

  • java.util.Observer
  • java.util.EventListener
  • javax.servlet.http.HttpSessionBindingListener
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值