### 1、使用定制“荷载”（payload）

此处借用框架内置的一个 “荷载” ReceivablePayload (一个普通的实体类)，发送可以再接收响应。

```java
public class ReceivablePayload<D,Rec> {
    private final D data;
    private final transient Rec sink;

    public ReceivablePayload(D data, Rec sink) {
        AssertUtil.notNull(sink, "The sink can not be null");

        this.data = data;
        this.sink = sink;
    }

    public D getData() {  return data; }
    public Rec getSink() {   return sink; }
}
```

应用示例：

```java
public class DemoApp {
    static String topic = "demo.hello";

    public static void main(String[] args) throws Exception {
        //监听事件
        Dami.bus().<ReceivablePayload<String, CompletableFuture<String>>>listen(topic, event -> {
            System.err.println(event.getPayload().getData());
            event.getPayload().getSink().complete("me to!");
        });

        //发送事件
        String rst = Dami.bus().<ReceivablePayload<String, CompletableFuture<String>>>send(topic, new ReceivablePayload<>("{name:'noear',say:'hello'}", new CompletableFuture<>()))
                .getPayload()
                .getReceiver()
                .get();
        System.out.println(rst);
    }
}
```

### 2、定制的演化

ReceivablePayload 提供了交互基础，但直接使用需要大串的泛型声明。下面使用另一个定制 “荷载”  CallPayload，指定了 “接收器” 为 CompletableFuture，这样会简化些：


```java
public class CallPayload<D,R> extends ReceivablePayload<D, CompletableFuture<R>> {
    public CallPayload(D data) {
        super(data, new CompletableFuture<>());
    }

    @Override
    public CompletableFuture<R> getSink() { return super.getSink(); }
}
```

应用演进示例：

```java
public class DemoApp {
    static String topic = "demo.hello";

    public static void main(String[] args) throws Exception {
        //监听事件
        Dami.bus().<CallPayload<String, String>>listen(topic, event -> {
            System.err.println(event.getPayload().getData());
            event.getPayload().getSink().complete("me to!");
        });

        //发送事件
        String rst = Dami.bus().<CallPayload<String, String>>send(topic, new CallPayload<>("{name:'noear',say:'hello'}"))
                .getPayload()
                .getReceiver()
                .get();
        System.out.println(rst);
    }
}
```


从框架的角度 “请求/响应” 这种模式是常见的存在。需要提供更简洁的体验。所以专门定制了简化接口：

```java
public class DemoApp {
    static String topic = "demo.hello";

    public static void main(String[] args) throws Exception {
        //监听事件
        Dami.bus().<String, String>listen(topic, (event, content, receiver) -> {
            System.err.println(content);
            receiver.complete("me to!");
        });

        //发送事件
        String rst = Dami.bus().<String, String>call(topic, "{name:'noear',say:'hello'}").get();
        System.out.println(rst);
    }
}
```

### 3、演化的终点，定制空接口（定制的过程，主要是固化泛型）

上面的杂乱主要是因为泛型的声明。下面以实现 call 效果为例，定制一个 DamiCall （名字随便取的）接口。

```java
public interface DamiCall {
    static DamiBus bus(){
        return Dami.bus();
    }
    
    //发送调用事件
    default <D, R> CompletableFuture<R> call(String topic, D data) {
        return call(topic, data, null);
    }

    //发送调用事件
    default <D, R> CompletableFuture<R> call(String topic, D data, Consumer<CompletableFuture<R>> fallback) {
        return callAsResult(topic, data, fallback).getPayload().getSink();
    }

    //发送调用事件
    default <D, R> Result<CallPayload<D, R>> callAsResult(String topic, D data) {
        return callAsResult(topic, data, null);
    }

    //发送调用事件
    default <D, R> Result<CallPayload<D, R>> callAsResult(String topic, D data, Consumer<CompletableFuture<R>> fallback) {
        if (fallback == null) {
            return bus().send(topic, new CallPayload<>(data));
        } else {
            return bus().send(topic, new CallPayload<>(data), r -> {
                fallback.accept(r.getSink());
            });
        }
    }

   //监听调用事件
    default <D, R> void listen(String topic, CallEventHandler<D, R> handler) {
        listen(topic, 0, handler);
    }

    //监听调用事件
    default <D, R> void listen(String topic, int index, CallEventHandler<D, R> handler) {
        bus().<CallPayload<D, R>>listen(topic, index, event -> {
            handler.onCall(event, event.getPayload().getData(), event.getPayload().getSink());
        });
    }
}
```

后续的应用效果：

```java
public class DemoApp {
     public static void main(String[] args) throws Exception {
        DamiCall.<String,String>listen("demo.hello", (event, data, sink) -> {
            sink.complete("hello " + data);
        });
        
        DamiCall.<String,String>call("demo.hello", "world");
    }
}
```


也可以给 listen 换个名字，比如叫：`onCall`（和 call 形成一对）

```java
public class DemoApp {
     public static void main(String[] args) throws Exception {
        DamiCall.<String,String>onCall("demo.hello", (event, data, sink) -> {
            sink.complete("hello " + data);
        });
        
        DamiCall.<String,String>call("demo.hello", "world");
    }
}
```


