设计模式梳理——观察者模式

本文详细介绍了观察者模式的原理及其实现方式,并通过对比展示了如何从双向耦合的实现过渡到解耦的设计,遵循了软件设计的最佳实践。

一、概述

       观察者模式(Observer),又叫发布-订阅(Publish/Subscribe)模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某个主题对象,这个主题对象发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 

二、UML图示

三、双向耦合编程实现

       1、主题类

public abstract class Subject {

    private List<Observer> observers = new ArrayList<>();


    /**
     * 增加观察者
     * @param observer
     */
    public void attach(Observer observer){
        observers.add(observer);
    }

    /**
     * 移除观察者
     * @param observer
     */
    public void detach(Observer observer){
        observers.remove(observer);
    }

    /**
     * 通知
     */
    public void notifyObservers(){
        for (Observer observer:observers) {
            observer.update();
        }
    }
}

2、观察者

public abstract class Observer {

    public abstract void update();
}

3、具体主题

public class ConcreteSubject extends Subject{

    private String subjectState;

    public String getSubjectState() {
        return subjectState;
    }

    public void setSubjectState(String subjectState) {
        this.subjectState = subjectState;
    }
}

4、具体观察者

public class ConcreteObserver extends Observer {

    private String name;
    private String observerState;
    private ConcreteSubject concreteSubject;

    public ConcreteObserver(String name, ConcreteSubject concreteSubject) {
        this.name = name;
        this.concreteSubject = concreteSubject;
    }

    public ConcreteSubject getConcreteSubject() {
        return concreteSubject;
    }

    public void setConcreteSubject(ConcreteSubject concreteSubject) {
        this.concreteSubject = concreteSubject;
    }

    @Override
    public void update() {
        observerState = concreteSubject.getSubjectState();
        System.out.println("观察者"+name+",新状态是:"+observerState);
    }
}

5、测试类

public class Test {

    public static void main(String[] args) {
        ConcreteSubject concreteSubject = new ConcreteSubject();
        concreteSubject.attach(new ConcreteObserver("aa",concreteSubject));
        concreteSubject.attach(new ConcreteObserver("bb",concreteSubject));
        concreteSubject.attach(new ConcreteObserver("cc",concreteSubject));
        concreteSubject.setSubjectState("ABC");
        concreteSubject.notifyObservers();
    }
}

输出:
观察者aa,新状态是:ABC
观察者bb,新状态是:ABC
观察者cc,新状态是:ABC

不难发现,上述代码存在几个严重问题:一是观察者与主题之间存在互相耦合;二是违背软件设计中的开发-封闭原则;三是违背软件设计中的依赖倒转原则,我们应该让程序都依赖抽象,而不是互相依赖。

四、解耦代码实现

1、主题接口

public interface Subject {


    /**
     * 增加观察者
     * @param observer
     */
    public void attach(Observer observer);

    /**
     * 移除观察者
     * @param observer
     */
    public void detach(Observer observer);

    /**
     * 通知
     */
    public void notifyObservers();
}

2、观察者接口

public interface Observer {

    void update(String message);
}

3、具体主题

public class ConcreteSubject implements Subject{

    //注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
    private List<Observer> list;
    private String message;

    public ConcreteSubject() {
        list = new ArrayList<>();
    }

    @Override
    public void attach(Observer observer) {
        list.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        list.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer o:list) {
            o.update(message);
        }
    }

    public void setInfomation(String s){
        this.message = s;
        System.out.println("服务器更新消息:"+s);
        //通知观察者
        notifyObservers();
    }
}

4、具体观察者

public class ConcreteObserver implements Observer {

    private String name;
    private String message;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        this.message = message;
        System.out.println(this.name+"收到消息:"+this.message);
    }
}

5、测试类

public class Test {

    public static void main(String[] args) {
        ConcreteSubject concreteSubject = new ConcreteSubject();
        Observer observer1 = new ConcreteObserver("aa");
        Observer observer2= new ConcreteObserver("bb");
        Observer observer3 = new ConcreteObserver("cc");
        concreteSubject.attach(observer1);
        concreteSubject.attach(observer2);
        concreteSubject.attach(observer3);
        concreteSubject.setInfomation("PHP是世界上最好的语言!");
    }
}
输出:
服务器更新消息:PHP是世界上最好的语言!
aa收到消息:PHP是世界上最好的语言!
bb收到消息:PHP是世界上最好的语言!
cc收到消息:PHP是世界上最好的语言!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值