深入浅出设计模式——从球赛中悟观察者模式

一、观察者模式概念

    观察者模式是指在对象之间定义一对多的依赖,当一个对象改变状态时,依赖它的对象都会收到通知并自动更新。

    就好比在足球比赛中,教练员会在场边发布命令,然后场上所有的队员都要根据它的命令作出响应,这时,场上的队员就是观察者,教练发出的口令就是主题。

二、使用场景

    在一个对象有改变其他依赖对象需要接到通知时

三、结构

     从上面的UML图中我们可以看出观察者模式由两个部分组成:

        1. 主题(Subject):也叫被观察者,如果主题发生改变那么观察者会接到通知

        2. 观察者(Observer)

四、实现

    在Java中可以通过继承JDK中的Observable类和实现Observer接口来实现观察者模式,但是不提倡这样做,因为Java是单继承语言,如果主题类需要用到观察者模式但同时它又继承了其他类,这样的情况就很尴尬。所以建议自己写主题类,况且这也不难实现。下面我们就从头开始自己实现观察者模式。

1. 定义主题接口

import observer.Observer;

/**
 * Description: 主题
 * Designer: jack
 * Date: 2017/8/7
 * Version: 1.0.0
 */
public interface Subject<T extends Subject> {
    void registerObserver(Observer<T> observer);    // 注册观察者

    void removeObserver(Observer observer);      //删除观察者

    void notifyObservers();      //当主题改变时,调用这个方法通知所有观察者
}

    接口中包含3个方法,注册观察者,删除观察者,和通知。这里对最基础的观察者模式做了一个小的拓展,那就是观察者可以自行注册和删除,当且仅当观察者在这个主题里注册了才会收到通知。

    (1)注册观察者:观察者如需订阅这个主题那么就调用注册方法,下一次主题改变时就会收到通知。

    (2)删除观察者:观察者如果不想再收到这个主题的通知则调用这个方法,以后主题再改变时也不会收到通知。

    (3)通知:主题发生改变时,调用这个方法通知已注册的观察者。

2. 观察者接口

import subject.Subject;

/**
 * Description: 观察者接口
 * Designer: jack
 * Date: 2017/8/7
 * Version: 1.0.0
 */
public interface Observer<T extends Subject> {
    void update(T t); //当需要改变战术时将新的战术通知给对应当球员
}

    观察者接口只需要一个update方法用于接受通知并做相应的处理。

3. 主题实现类

package subject;

import observer.Observer;

import java.util.ArrayList;
import java.util.stream.Collectors;

/**
 * Description: 球员战术指示
 * Designer: jack
 * Date: 2017/8/7
 * Version: 1.0.0
 */
public class PositionAndStrategy implements Subject<PositionAndStrategy>{

    private ArrayList<Observer<PositionAndStrategy>> observers;  //观察者注册信息列表
    private String strikerStrategy;     //前锋战术指令
    private String defenderStrategy;    //后卫战术指令

    public PositionAndStrategy() {
        this.observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer<PositionAndStrategy> observer) {
        this.observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        this.observers = this.observers.stream()
                .filter(observer1 -> !observer1.equals(observer))
                .collect(Collectors.toCollection(ArrayList::new));
    }

    @Override
    public void notifyObservers() {
        this.observers.forEach(observer -> observer.update(this));
    }

    public void setStrategy(String strikerStrategy, String defenderStrategy) {
        this.strikerStrategy = strikerStrategy;
        this.defenderStrategy = defenderStrategy;
        notifyObservers();
    }

    public String getStrikerStrategy() {
        return strikerStrategy;
    }

    public String getDefenderStrategy() {
        return defenderStrategy;
    }
}

    主题实现类包含了所有观察者所需要的所有信息,并且在信息发生改变时(setStrategy)调用notifyObservers()方法向观察者发送通知。notifyObservers()实现的方法就是调用observers列表中的每一个观察者的update()方法。

4. 观察者实现

    第一个观察者:前锋

import subject.PositionAndStrategy;

/**
 * Description: 前锋
 * Designer: jack
 * Date: 2017/8/7
 * Version: 1.0.0
 */
public class Striker implements Observer<PositionAndStrategy>{

    @Override
    public void update(PositionAndStrategy positionAndStrategy) {
        //他只需要执行前锋的战术就好了,不用管后卫是什么战术
        System.out.println("前锋:" + positionAndStrategy.getStrikerStrategy() );
    }

}

    第二个观察者:后卫

import subject.PositionAndStrategy;

/**
 * Description:
 * Designer: jack
 * Date: 2017/8/7
 * Version: 1.0.0
 */
public class Defender implements Observer<PositionAndStrategy>{

    @Override
    public void update(PositionAndStrategy positionAndStrategy) {
        System.out.println("后卫:" + positionAndStrategy.getDefenderStrategy() );
    }

}

    主题类将所有的信息都交给观察者,而观察者从里面取出自己需要的信息进行处理就可以了。

5. 实现类

import observer.Defender;
import observer.Striker;
import subject.PositionAndStrategy;

public class Main {
    public static void main(String[] args) {
        //创建战术板(主题类)
        PositionAndStrategy positionAndStrategy = new PositionAndStrategy();

        //创建前锋和后卫(观察者)
        Striker striker = new Striker();
        Defender defender = new Defender();

        //在主题中注册观察者
        positionAndStrategy.registerObserver(striker);
        positionAndStrategy.registerObserver(defender);
        //主题发生变化
        System.out.println("主题第一次变化!");
        positionAndStrategy.setStrategy("进攻", "防守");

        //现在后卫距离太远,听不到教练的指令了(删除观察者)
        positionAndStrategy.removeObserver(defender);
        //主题发生变化
        System.out.println("\n主题第二次变化");
        positionAndStrategy.setStrategy("继续进攻", "压上支援");

        //后卫现在又能听到指令了
        positionAndStrategy.registerObserver(defender);
        //主题发生变化
        System.out.println("\n主题第三次变化");
        positionAndStrategy.setStrategy("表现的不错,保持住", "后卫你们在干什么,叫你们压上支援");
    }
}

    执行main方法得到结果:

    可以看出主题每一次变化订阅了主题的观察者都能收到相应的通知,然后他们从里面提取自己需要的信息进行处理。这就是观察者模式。

五、优点

    1. 观察者与被观察者之间的耦合度低

    2. 有一套触发机制

六、局限性

    1. 如果一个主题中观察者过多会导致效率降低。

    2. 观察者只知道主题变化的结果而不知道主题是怎么变化的。

    世界上没有十全十美的模式,每个设计模式都有它适用的地方,只要我们的使用方式得当,那么观察者模式可以帮助我们写出漂亮优雅的代码。

附源码地址:http://git.oschina.net/jack90john/observer

------------------------------------------------------------------------------

欢迎关注我的个人公众号,推送最新文章

转载于:https://my.oschina.net/jack90john/blog/1504443

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值