当前位置: 首页 > 工具软件 > Ambassador > 使用案例 >

设计模式-大使模式(Ambassador)

靳彦
2023-12-01

目的:创建代表消费者服务或应用程序发送网络请求的帮助服务。

使用场景:大使适用于无法修改或极难修改的旧式远程服务。 可以在客户端上实现连接性的功能,而无需更改远程服务。

1.创建远程服务和大使服务共享的接口

interface RemoteServiceInterface {

  long doRemoteFunction(int value);
}

2.创建单例的远程服务

public class RemoteService implements RemoteServiceInterface {

 private static final Logger LOGGER =  LoggerFactory.getLogger(RemoteService.class.getName());

 private  static  RemoteService service=null;

 static synchronized RemoteService getRemoteService(){

     if (service==null){
         service=new RemoteService();
     }
     return service;
 }

    public RemoteService() {
    }

    @Override
    public long doRemoteFunction(int value) {
        long waitTime = (long) Math.floor(Math.random() * 1000);

        try {
            Thread.sleep(waitTime);
        } catch (InterruptedException e) {
            LOGGER.error("Thread sleep interrupted",e);
        }

        return waitTime>=200?value*10:-1;
    }
}

3.创建大使代理,增加日志和延迟检测的额外功能

// 状态枚举
public enum RemoteServiceStatus {
    FAILURE(-1);
    private final long remoteServiceStatusValue;

    public long getRemoteServiceStatusValue() {
        return remoteServiceStatusValue;
    }

    RemoteServiceStatus(long remoteServiceStatusValue) {
        this.remoteServiceStatusValue = remoteServiceStatusValue;
    }
}
@Slf4j
public class ServiceAmbassador implements RemoteServiceInterface {

    private static final int RETRIES = 3;
    private static final int DELAY_MS = 3000;

    public ServiceAmbassador() {
    }

    @Override
    public long doRemoteFunction(int value) throws Exception {

        return safeCall(value);
    }

    /**
     * 检查时延
     * @param value
     * @return
     */
    private long checkLatency(int value) {
        long startTime = System.currentTimeMillis();
        long result = RemoteService.getRemoteService().doRemoteFunction(value);
        long timeTaken = System.currentTimeMillis() - startTime;
        log.info("Time taken (ms) :{}", timeTaken);
        return result;
    }

    /**
     * 安全呼叫
     * @param value
     * @return
     */
    private long safeCall(int value) {
        long retries = 0;
        long result = FAILURE.getRemoteServiceStatusValue();
        for (int i = 0; i < RETRIES; i++) {
            //重试次数大于3,返回失败码
            if (retries >= RETRIES) {
                return FAILURE.getRemoteServiceStatusValue();
            }
            //失败记录+1
            if ((result = checkLatency(value)) == FAILURE.getRemoteServiceStatusValue()) {
                log.info("Failed to reach remote:({})", i + 1);
                retries++;

                try {
                    Thread.sleep(DELAY_MS);
                } catch (InterruptedException e) {
                    log.error("Thread sleep state interrupted", e);
                    Thread.currentThread().interrupt();
                }
            } else {
                break;
            }


        }
        return result;
    }
}

4.创建客户端,具有用于与远程服务进行交互的本地服务大使

@Slf4j
public class Client {
    private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador();

    @SneakyThrows
    long useService(int value) {
        long result = serviceAmbassador.doRemoteFunction(value);
        log.info("Service result:{}", result);
        return result;
    }
}

5.测试

    Client c1 = new Client();
        Client c2 = new Client();
        c1.useService(12);
        c2.useService(73);


输出:
 Time taken (ms) :15
 Failed to reach remote:(1)
 Time taken (ms) :221
 Service result:120
 Time taken (ms) :234
 Service result:730

 类似资料: