发布订阅和FutureTask实现FutureTask的get方法的自动回调执行

248 阅读3分钟

主类测试代码

package com.designpattern.pubsubpattern;

import com.designpattern.pubsubpattern.sub.Subscriber;

public class Main {
    public static void main(String[] args) {
        new CallBackFacade<String>(()-> {
            return "helloworld";
        }).then(new Subscriber<String>() {
            @Override
            public void onSuccess(String result) {
                System.out.println("成功:" + result);
            }
            @Override
            public void onFailure() {
                System.out.println("失败");
            }
        }).then(new Subscriber() {
            @Override
            public void onSuccess(Object result) {
                System.out.println("又成功了:" + result);
            }

            @Override
            public void onFailure() {
                System.out.println("又失败了");
            }
        }).ok();
    }
}

对外的统一使用接口

package com.designpattern.pubsubpattern;

import com.designpattern.pubsubpattern.manager.Manager;
import com.designpattern.pubsubpattern.message.Message;
import com.designpattern.pubsubpattern.pub.Publisher;
import com.designpattern.pubsubpattern.sub.Subscriber;

import java.util.concurrent.*;

public class CallBackFacade<T> {

    private int nThreads = 0;
    private Manager manager;
    private Publisher publisher;
    private FutureTask<T> futureTask;
    private ExecutorService executorService;
    private CountDownLatch countDownLatch;


    private CallBackFacade(){

    }

    public CallBackFacade(Callable<T> callable) {
        manager = new Manager();
        publisher = new Publisher(manager);
        futureTask = new FutureTask<T>(callable);
        executorService = Executors.newCachedThreadPool(Executors.defaultThreadFactory());
    }

    public CallBackFacade<T> then(Subscriber subscriber) {
        subscriber.setManager(manager);
        subscriber.subscribeTopic("hello");
        nThreads ++;
        executorService.execute(()->{
            try {
                T t = futureTask.get();
                publisher.publish(new Message().setSuccess(true).setResult(t).setTopic("hello"));
            } catch (Exception e) {
                publisher.publish(new Message().setSuccess(false).setTopic("hello"));
            }
            countDownLatch.countDown();
        });
        return this;
    }

    public void ok() {
        countDownLatch = new CountDownLatch(nThreads);
        executorService.execute(futureTask);
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }

}

发布的消息

package com.designpattern.pubsubpattern.message;

import java.util.Objects;

/**
 * 主题
 */
public class Message<Result> {

    /**
     * 成功时的返回结果
     */
    private Result result = null;

    /**
     * 是否成功
     */
    private boolean success = false;

    /**
     * 主题
     */
    private String topic = "";

    /**
     * 无参构造方法,没啥用
     */
    public Message() {
        result = null;
    }

    /**
     * 成功时用,需要主题,结果等信息,成功为是
     * @param topic 主题
     * @param result 结果
     */
    public Message(String topic, Result result) {
        this.setSuccess(true).setResult(result).setTopic(topic);
    }

    /**
     * 失败时用,只需要主题,不需要结果,成功为否
     * @param topic 主题
     */
    public Message(String topic) {
        this.setSuccess(false).setTopic(topic);
    }

    /**
     * 返回成功与否
     * @return 成功与否
     */
    public boolean isSuccess() {
        return success;
    }

    /**
     * 设置返回结果
     * @param result 返回结果
     * @return 返回this指针,方便链式调用
     */
    public Message<Result> setResult(Result result) {
        this.result = result;
        return this;
    }

    /**
     * 设置是否成功
     * @param success 成功信息
     * @return 返回this指针,方便链式调用
     */
    public Message<Result> setSuccess(boolean success) {
        this.success = success;
        return this;
    }

    /**
     * 设置主题
     * @param topic 主题
     */
    public Message setTopic(String topic) {
        this.topic = topic;
        return this;
    }

    public Result getResult() {
        return result;
    }

    public String getTopic() {
        return topic;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Message<?> message = (Message<?>) o;
        return success == message.success && Objects.equals(result, message.result) && Objects.equals(topic, message.topic);
    }

    @Override
    public int hashCode() {
        return Objects.hash(result, success, topic);
    }
}

管理者(订阅者的注册和发现中心)

package com.designpattern.pubsubpattern.manager;

import com.designpattern.pubsubpattern.message.Message;
import com.designpattern.pubsubpattern.sub.Subscriber;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

/**
 * 发布-订阅模式的管理者。
 * 对某一主题而言订阅者的注册和发现中心。
 * 功能类似Spring的IOC容器。
 * 或者微服务框架的服务注册和发现的中心。
 */
public class Manager {

    /**
     * 以主题为键,以订阅者为值的字典
     * 勉强使用着,如果在多线程线程环境下,
     * 要换成ConcurrentHashmap或者ConcurrentSkipListMap
     */
    private HashMap<String, Set<Subscriber>> messageSetHashMap = new HashMap<>();


    /**
     * 固定长度的线程池
     * 用于异步调用的订阅者的通知
     * 勉强使用着,根据具体情况再调整
     */
//    private ExecutorService executorService = Executors.newFixedThreadPool(10);

    /**
     * 添加订阅者
     * @param topic 主题
     * @param subscriber 订阅者
     */
    public void addSubscriber(String topic, Subscriber subscriber) {
        /**
         * 参数不能为空
         */
        if (topic == null || subscriber == null) {
            throw new NullPointerException("空指针异常了吧!");
        }
        /**
         * 字典里没有这个键的话,添加进去,并new一个HashSet作为订阅者的容器
         */
        if (!messageSetHashMap.containsKey(topic)) {
            messageSetHashMap.put(topic, new HashSet<>());
        }
        /**
         * 在主题键所对应的订阅者集合值的容器中添加订阅者
         */
        messageSetHashMap.get(topic).add(subscriber);
    }

    /**
     * 移除订阅者
     * @param topic 主题
     * @param subscriber 订阅者
     */
    public void removeSubscriber(String topic, Subscriber subscriber) {
        /**
         * 只有在键中含有这个topic,才有必要移除订阅者
         */
        if (messageSetHashMap.containsKey(topic)) {
            messageSetHashMap.get(topic).remove(subscriber);
        }
    }


    /**
     * 发布消息,并给所有订阅者发消息(调用所有订阅者的方法)
     * @param message
     */
    public void publish(Message message) {
        /**
         *  订阅者集合
          */
        Set<Subscriber> subscriberSet = messageSetHashMap.get(message.getTopic());

        /**
         * 同步调用
         */
        for (Subscriber subscriber : subscriberSet) {
            /**
             * 成功
             */
            if (message.isSuccess()) {
                subscriber.onSuccess(message.getResult());
            } else {
                /**
                 * 失败
                 */
                subscriber.onFailure();
            }
        }

        /**
         * 异步调用
         */
        // todo 线程池提交
    }

}

发布者

package com.designpattern.pubsubpattern.pub;

import com.designpattern.pubsubpattern.manager.Manager;
import com.designpattern.pubsubpattern.message.Message;

/**
 * 发布者
 */
public class Publisher {

    /**
     * 发布-订阅模式的管理者
     */
    private Manager manager;

    /**
     * 无参构造方法,肯定用不上
     */
    public Publisher() { }

    /**
     * 有参构造方法,就是用来设置进来
     * @param manager
     */
    public Publisher(Manager manager) {
        this.manager = manager;
    }

    public void publish(Message message) {
        manager.publish(message);
    }
}

订阅者抽象类

package com.designpattern.pubsubpattern.sub;

import com.designpattern.pubsubpattern.manager.Manager;

/**
 * 订阅者
 */
public abstract class Subscriber<T> {

    protected Manager manager;

    public Subscriber() { }

    public Subscriber(Manager manager) {
        this.manager = manager;
    }

    public void setManager(Manager manager) {
        this.manager = manager;
    }

    /**
     * 订阅某主题
     * @param topic 主题
     */
    public void subscribeTopic(String topic) {
        manager.addSubscriber(topic, this);
    }

    /**
     * 退订某主题
     * @param topic 主题
     */
    public void unsubscribeTopic(String topic) {
        manager.removeSubscriber(topic, this);
    }

    public abstract void onSuccess(T result);

    public abstract void onFailure();

}