设计模式之观察者模式

本文主要为大家介绍观察者模式的定义,特点以及如何实现一个观察者模式。在手动实现观察者模式之后,也会为大家介绍JDK内置观察者模式的使用。

定义

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式的特点就是观察者和被观察者是抽象耦合的。被观察者只知道观察者对象实现了公共的接口(Observer),不知道观察者对象具体是谁,更加不知道它们的行为。另外,我们可以任意的添加或者删除观察者,被观察者不会受到任何影响。使用观察者模式,我们可以设计出很好的松耦合系统。

使用场景

1.当一个对象更新时,需要同步其它对象的状态,并且其它对象的数量是不确定的。

2.对象只需要将自身更新状态通知过去,不需要知道其它对象细节。

自定义实现

在实现观察者模式的时候,我们通常需要依赖两种类型的对象:观察者和被观察者。通常我们又把被观察者叫做主题,观察者又被叫做订阅者。大家试想一下,如果我们自己实现观察者模式,我们应该怎样开始呢?上面已经介绍到观察者模式中的对象是一对多的关系,不难猜测出这种关系应该是被观察者 1—— n 观察者,要想实现这种关系,那么被观察者对象就需要包含观察者对象的集合,这样才能在自身内部发生变化的时候,把这种变化传递给观察者对象。观察者需要向被观察者注册、注销自己,那么就需要包含被观察者的对象。通过我们的推测,代码大概是这个样子的:

被观察者类(主题)

public class Subject {
    //用于判断主题(被观察者)自身状态是否改变
    boolean changed = false;
    //具体内容
    String message;
    //用于存放注册的观察者(订阅者)
    private List<Observer> observers = new ArrayList<>();

    public void add(Observer observer) {
        this.observers.add(observer);
    }

    public void remove(Observer observer) {
        this.observers.remove(observer);
    }

    public void setMessage(String message) {
        this.message = message;
        this.changed = true;
        notifyObservers();
    }

    //用于通知所有观察者
    public void notifyObservers() {
        if (changed) {
            for (Observer observer : observers) {
                observer.update(this.message);
            }
            this.changed = false;
        }
    }
}

观察者类(订阅者):

public interface Observer {
    void update(String message);
}

//观察者一
class FirstObserver implements Observer {
    //被观察类
    private Subject subject;

    public FirstObserver(Subject subject) {
        this.subject = subject;
        this.subject.add(this);
    }

    @Override
    public void update(String message) {
        System.out.println("观察者一接受到消息:" + message);
    }
}

//观察者二
class SecondObserver implements Observer {
    //被观察类
    private Subject subject;

    public SecondObserver(Subject subject) {
        this.subject = subject;
        this.subject.add(this);
    }

    @Override
    public void update(String message) {
        System.out.println("观察者二接受到消息:" + message);
    }
}

测试:

Subject subject = new Subject();
FirstObserver firstObserver = new FirstObserver(subject);
SecondObserver secondObserver = new SecondObserver(subject);
subject.setMessage("华为投诉美国政府");
subject.setMessage("5G时代即将来临");

上述是我们自己实现的一个简单版的观察者模式,核心内容基本就是这些,但是我们仔细观察,这里面还是有很大的问题的,例如我们的集合使用的是List,这样可能会导致一个对象被注册多次,另外我们上述的注册和注销操作都没有考虑线程不安全的情况,在多线程操作的情况下,可能出现异常。当然,当我们知道这些问题之后,可以继续优化,但是有这个必要吗?其实,JDK已经为广大开发者提供了观察者与被观察者的实现,我们自己写观察者模式,只是为了加深对它的了解,更多的时候不需要我们自己去实现,当然,自己实现也比较简单。

JDK观察者模式实现

上述我们所实现的观察者模式,是一个典型的推模式,也就是被观察者主动推送消息给观察者对象,无需观察者手动获取消息,这是我们通常使用的方式。在某些特殊的情况下,各个观察者可能需要的消息内容不一样,没有必要全部推送,这个时候就可以使用拉模式。JDK已经很好的实现了两种方式,现在我们就来具体使用一下。

被观察者:通过继承Observable来实现,已经封装好注册、注销观察者相关方法。

public class NewsObservable extends Observable {
    //技术类新闻
    private String technology;
    //娱乐新闻
    private String entertainment;
    //军事新闻
    private String military;

    public void changed() {
        //改变自身状态
        setChanged();
        //这里使用推模式传递消息,通知完毕后,改变状态会被清空
        notifyObservers(this.technology);
    }

    //用于修改新闻
    public void setNews(String technology, String entertainment, String military) {
        this.technology = technology;
        this.entertainment = entertainment;
        this.military = military;
        changed();
    }

    public String getTechnology() {
        return technology;
    }

    public String getEntertainment() {
        return entertainment;
    }

    public String getMilitary() {
        return military;
    }

}

观察者:通过implements Observer实现观察者。

public class CustomObserver implements Observer {

    //Observable就是我们的被观察对象
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("获得消息:" + arg);
    }
}

测试:

NewsObservable newsObservable = new NewsObservable();
CustomObserver customObserver1 = new CustomObserver();
CustomObserver customObserver2 = new CustomObserver();
//用于注册观察者
newsObservable.addObserver(customObserver1);
newsObservable.addObserver(customObserver2);
newsObservable.setNews("技术新闻", "娱乐新闻", "军事新闻");
//用于注销观察者
newsObservable.deleteObserver(customObserver2);
newsObservable.setNews("技术新闻1", "娱乐新闻1", "军事新闻1");

上述在被观察者类中,我们使用notifyObservers(Object args);方法进行通知观察者对象,该方法在传递参数的时候就是推模式,不传递参数的时候就是拉模式。如果我们想使用拉模式获取消息,如下操作:

@Override
public void update(Observable o, Object arg) {
    NewsObservable newsObservable= (NewsObservable)o;
    System.out.println("获得消息:" + newsObservable.getEntertainment()+":"+newsObservable.getTechnology());
}

采用JDK内置的观察者模式实现,我们无需关注观察者的注册、注销等相关行为,并且内置的观察者模式采用Vector保存观察者对象以及使用synchronized,保证了在多线程使用中能够做到线程安全,大家有空可以去看看源码,比较简单。

总结

观察者模式有助于我们建立松耦合的系统,针对不同的业务环境,大家可以采用推模式或拉模式。JDK提供内置观察者模式供开发者使用,若不能满足大家的需求,手动实现也是比较简单。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值