每天一个设计模式之观察者模式+发布订阅模式(Observer Pattern)

观察者模式定义了一套机制,可以实现一对多的关系,当“一”(被观察者)的状态发生了变化,会通知“多”个(观察者),这是行为型模式。

一、场景示例

在这里插入图片描述
这个模式存在这样的一个问题:如果由观察者不停地查询被观察者的状态变化,那么观察者将苦不堪言;而如果由被观察者来通知所有的观察者,那么有些对该状态不感兴趣的观察者将会“抱怨”。
在这里插入图片描述

二、观察者模式 vs 发布-订阅模式

  1. 观察者模式,Subject和Observer是紧耦合的关系,而pub-sub是松散耦合,中间隔着event channel(或者称message broker);
  2. sub-obs直接发送消息,属于同步;而pub-sub则中间有一个消息队列,属于异步;
  3. sub-obs缺点多多,Java 9已经去掉了官方观察者模式的实现;而pub-sub适用范围更广,在分布式系统中更是常见。

在这里插入图片描述

二、代码示例 - 观察者模式

观察者抽象类

public abstract class Observer {
    protected Subject subject;
    public abstract void update();
}

具体观察者

public class HexObserver extends Observer {

    public HexObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Hex string: " + subject.getState());
    }
}

public class OctalObserver extends Observer {

    public OctalObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Octal string: " + subject.getState());
    }
}

public class BinaryObserver extends Observer {

    public BinaryObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Binary string: " + subject.getState());
    }
}

被观察者(主题类)

public class Subject {
    private int state;
    private List<Observer> observers = new ArrayList<>();

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        notifyAllObservers();
    }

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

    public void notifyAllObservers() {
        for (Observer o : observers) {
            o.update();
        }
    }
}

客户类

public class Client {
    public static void main(String[] args) {
        Subject subject = new Subject();

        new HexObserver(subject);
        new BinaryObserver(subject);
        new OctalObserver(subject);

        System.out.println("First state changes: 111");
        subject.setState(111);

        System.out.println("--------------------------");

        System.out.println("Second state changes: 222");
        subject.setState(222);
    }
}

运行结果

First state changes: 111
Hex string: 111
Binary string: 111
Octal string: 111
--------------------------
Second state changes: 222
Hex string: 222
Binary string: 222
Octal string: 222

Process finished with exit code 0

三、代码示例 - 发布-订阅模式

发布者

public class Publisher {

    public Publisher(Integer pubId) {
        this.pubId = pubId;
    }

    private Integer pubId;

    public Integer getPubId() {
        return pubId;
    }

    public void setPubId(Integer pubId) {
        this.pubId = pubId;
    }

    @Override
    public String toString() {
        return "Publisher{" +
                "pubId=" + pubId +
                '}';
    }
}

订阅者

public class Subscriber {
    public Subscriber(Integer subId) {
        this.subId = subId;
    }

    private Integer subId;

    public Integer getSubId() {
        return subId;
    }

    public void setSubId(Integer subId) {
        this.subId = subId;
    }

    @Override
    public String toString() {
        return "Subscriber{" +
                "subId=" + subId +
                '}';
    }
}

消息类

public class Message {
    public Message(String content) {
        this.content = content;
    }

    private String content;

    @Override
    public String toString() {
        return "Message{" +
                "content='" + content + '\'' +
                '}';
    }
}

发布-订阅控制中心

public interface SubPubCentral {
    boolean subscribe(Publisher publisher, Subscriber subscriber);
    boolean unsubscribe(Publisher publisher, Subscriber subscriber);
    void publish(Publisher publisher, Message message);
}

public class SubPubCentralImpl implements SubPubCentral {
    private static Map<Integer, Set<Integer>> pubSubMap;

    static {
        pubSubMap = new HashMap<>();
    }
    @Override
    public boolean subscribe(Publisher publisher, Subscriber subscriber) {
        Set<Integer> subscribeSet = pubSubMap.getOrDefault(publisher.getPubId(), new HashSet<>());
        boolean add = subscribeSet.add(subscriber.getSubId());
        if (add) pubSubMap.put(publisher.getPubId(), subscribeSet);
        return pubSubMap.size() > 0;
    }

    @Override
    public boolean unsubscribe(Publisher publisher, Subscriber subscriber) {
        Set<Integer> subscribeSet = pubSubMap.get((publisher.getPubId()));
        boolean remove = false;
        if (subscribeSet != null && subscribeSet.size() > 0) {
            remove = subscribeSet.remove(subscriber.getSubId());
            if (remove) pubSubMap.put(publisher.getPubId(), subscribeSet);
        }
        return remove;
    }

    @Override
    public void publish(Publisher publisher, Message message) {
        Set<Integer> subscribeSet = pubSubMap.get((publisher.getPubId()));
        for (Integer id : subscribeSet) {
            System.out.println("向发布者[" + publisher.getPubId() + "]的订阅者[" + id + "]发送消息:" + message);
        }
    }
}

发布控制器和订阅控制器

public class PublisherController {
    private SubPubCentral subPubCentral;

    public PublisherController(SubPubCentral subPubCentral) {
        this.subPubCentral = subPubCentral;
    }

    public void publish(Integer pubId, String message) {
        subPubCentral.publish(new Publisher(pubId), new Message(message));
    }
}

public class SubscribeController {
    private SubPubCentral subPubCentral;

    public SubscribeController(SubPubCentral subPubCentral) {
        this.subPubCentral = subPubCentral;
    }

    public void sub(Integer subId, Integer pubId) {
        subPubCentral.subscribe(new Publisher(pubId), new Subscriber(subId));
    }

    public void unsub(Integer subId, Integer pubId) {
        subPubCentral.unsubscribe(new Publisher(pubId), new Subscriber(subId));
    }
}

客户类

public class Client {
    public static void main(String[] args) {
        SubPubCentral subPubCentral = new SubPubCentralImpl();

        PublisherController publisherController = new PublisherController(subPubCentral);
        SubscribeController subscribeController = new SubscribeController(subPubCentral);

        subscribeController.sub(100, 001);
        subscribeController.sub(101, 001);

        publisherController.publish(001, "from#001 publish, COVID-19 regions of high risk");
        System.out.println("~~~~~~~~~~~~~~~~~~");

        subscribeController.unsub(100, 001);
        publisherController.publish(100, "$$%%$$");
    }
}

【参考】

  1. https://blog.csdn.net/David_TD/article/details/107715396
  2. https://embeddedartistry.com/fieldatlas/differentiating-observer-and-publish-subscribe-patterns/
  3. https://www.runoob.com/design-pattern/observer-pattern.html
  4. https://refactoring.guru/design-patterns/observer

设计模式系列博文导航

一、创建型 - 5种

原型模式(Prototype Pattern)
抽象工厂模式(Abstract Factory Pattern)
建造者模式(Builder Pattern)
工厂模式(Factory Pattern)
单例模式(Singleton Pattern)

助记语:原抽建工单

二、结构型 - 8种

享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
适配器模式(Adapter Pattern)
外观模式(Facade Pattern)

过滤器模式(Filter/Criteria Pattern)
桥接模式(Bridge Pattern)
组合模式(Composite Pattern)
装饰器模式(Decorator Pattern)

助记语:想呆室外,过桥组装

三、行为型 - 11种

责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
中介者模式(Mediator Pattern)
迭代器模式(Iterator Pattern)

观察者模式(Observer Pattern)
策略模式(Strategy Pattern)
状态模式(State Pattern)

备忘录模式(Memento Pattern)
模板方法模式(Template Pattern)
访问者模式(Visitor Pattern)

助记语:责令解中谍,观测状被模仿

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值