發佈訂閱模式
該模式主要涉及三個類型對象: 發佈者、發佈訂閱管理器、訂閱者;
設計原理
發佈者將消息發佈到管理器上, 訂閱者從管理器訂閱消息;這樣將發佈者和訂閱者進行了解耦,實現了鬆耦合;
實現代碼實例
1、發佈者
package com.jt.designModel.subscriber;
public class PublisherImpOne<T> implements Ipublisher<T> {
private String name;
public PublisherImpOne(String name) {
super();
this.name = name;
}
@Override
public void publish(SubscribePublish<T> subscribePublish, T message, boolean isInstantMsg) {
subscribePublish.publish(this.name, message, isInstantMsg);
}
}
2、管理器
package com.jt.designModel.subscriber;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;public class SubscribePublish<T> {
//訂閱器名稱
private String name;
//訂閱器隊列容量
final int QUEUE_CAPACITY = 20;
//訂閱器存儲隊列
private BlockingQueue<Msg<T>> queue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
//訂閱者
private List<ISubcriber<T>> subcribers = new ArrayList<>();
public SubscribePublish(String name) {
this.name = name;
}
public void publish(String publisher, T message, boolean isInstantMsg) {
//true
if (isInstantMsg) {
update(publisher, message);
return;
}
Msg<T> m = new Msg<T>(publisher, message);
if (!queue.offer(m)) {
update();
}
}
public void subcribe(ISubcriber<T> subcriber) {
subcribers.add(subcriber);
}
public void unSubcribe(ISubcriber<T> subcriber) {
subcribers.remove(subcriber);
}
public void update() {
Msg<T> m = null;
while ((m = queue.peek()) != null) {
this.update(m.getPublisher(), (T) m.getMsg());
}
}
public void update(String publisher, T Msg) {
for (ISubcriber<T> subcriber : subcribers) {
subcriber.update(publisher, Msg);
}
}
}
class Msg<T> {
private String publisher;
private T m;
public Msg(String publisher, T m) {
this.publisher = publisher;
this.m = m;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public T getMsg() {
return m;
}
public void setMsg(T m) {
this.m = m;
}
}
3、訂閱者
package com.jt.designModel.subscriber;
public class SubcriberImpOne<T> implements ISubcriber<T> {
public String name;
public SubcriberImpOne(String name) {
super();
this.name = name;
}
@Override
public void subcribe(SubscribePublish<T> subscribePublish) {
subscribePublish.subcribe(this);
}@Override
public void unSubcribe(SubscribePublish<T> subscribePublish) {
subscribePublish.unSubcribe(this);
}@Override
public void update(String publisher, T message) {
System.out.println(this.name + "收到" + publisher + "發來的消息:" + message.toString());
}}
4、測試類
package com.jt.designModel.subscriber;
public class Test {
public static void main(String[] args) {
SubscribePublish<String> subscribePublish = new SubscribePublish<String>("訂閱器");
Ipublisher<String> publisher1 = new PublisherImpOne<>("發佈者1");
Ipublisher<String> publisher2 = new PublisherImpOne<>("發佈者2");ISubcriber<String> subcriber = new SubcriberImpOne<String>("訂閱者1");
subcriber.subcribe(subscribePublish);
// 發佈消息
publisher1.publish(subscribePublish, "welcome", true);
publisher1.publish(subscribePublish, "to", true);
publisher2.publish(subscribePublish, "你好", true);
}}
5、測試結果
訂閱者1收到發佈者1發來的消息:welcome
訂閱者1收到發佈者1發來的消息:to
訂閱者1收到發佈者2發來的消息:你好
總結
發佈訂閱模式, 主要是通過訂閱器達到和發佈者之間的鬆耦合關係;該模式可用在消息推送類型的場景;在我所在的項目中, 由於數據庫表存在冗餘的消息, 在更新基礎表信息時,需要將冗餘的信息同步更改。 也可以採用該模式;在分佈式項目中,也可以採用消息中間件 來實現多個項目的一致性。
該模式和觀察者模式之間的區別, 主要的區別就在於,是否存在 管理器;觀察者模式中, 觀察者和發佈者之間存在耦合, 即觀察者需要註冊到發佈者對象上, 這樣,發佈者在發佈時, 會執行觀察者的相應方法;下圖藉助於網上,能夠比較清晰的區分這兩種模式的區別: