简介:
在面对对象编程中,命令模式是一种行为模式,其中对象用于封装执行动作或稍后触发事件所需的所有信息。这些信息包括方法名称,拥有该方法的对象以及方法参数的值。命令模式也支持可撤销操作。
命令模式包括4个角色:
Command:定义命令的统一接口
ConcreteCommand:Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。
Receiver:命令的实际执行者
Invoker:命令的请求者,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。
命令模式有如下优点:
1.降低对象之间的耦合度(将发出请求的对象和执行请求的对象解耦,即将调用者和执行者进行解耦)
2.新的命令可以很容易地加入到系统中。
3.可以比较容易地设计一个组合命令。
4.调用同一方法实现不同的功能
缺点:
可能会导致某些系统有过多的具体命令类。
Hystrix
Hystrix命令模式封装了命令运行逻辑(run)和服务调用失败时回退逻辑(getFallback)。其command抽象类是hystrixcommand,用于包装执行具有潜在风险功能的代码(通常指通过网络进行的服务调用),具备容错和延时,统计和性能指标捕获,断路器和舱壁功能。
该命令本质上是一个阻塞命令,但如果与observe()一起使用,则提供一个可观察的facade。
此模式的详情如下:
- 构造Hystrix命令对象,并调用run方法
- Hystrix将检查断路器开关是否打开,如果打开,则调用回退方法
- 如果断路器开关关闭,Hystrix将检查当前服务的线程池,看是否可以接受新请求。如果线程池已满,则调用回退方法
- 如果线程池可以接受新请求,那么Hystrix可以调用run方法来执行run逻辑
- 如果run执行失败,则调用回退方法并将健康状态返回到Hystrix指标
- 如果run执行超时,则调用回退方法并将健康状况返回到Hystrix指标
- 如果run成功执行,则返回正常结果
- 如果回退方法成功执行,它将返回回退执行结果
- 如果回退方法执行失败,则抛出异常
伪代码示例子
那是否使用命令模式,这两者有什么区别呢?我们通过一些伪代码来帮助理解.
有hystrixcommand之前:
代码语言:javascript复制public class SimpleHystrix {
private RestService restService;
private HttpClientService httpClientService;
private OkHttpService okHttpService;
public void call(String callName) {
if (callName.equals("httpclient")) {
httpClientService.do();
} else if (callName.equals("okhttpclient")) {
okHttpService.do();
} else if (callName.equals("restClient")) {
restService.do();
}
}
}
public class SimpleHystrixRun {
public static void main(String[] args) {
SimpleHystrix simpleHystrix = new SimpleHystrix();
simpleHystrix.call("httpclient");
simpleHystrix.call("okhttpclient");
simpleHystrix.call("restClient");
}
}
这里需要根据指令来调用对象的方法,如果需要新增command类型,那么就需要在SimpleHystrix里增加判断,这样SimpleHystrix始终要关注需要调用的外部服务,如果新增服务时需要改动代码,这样违背了面向接口编程的原则,同时代码也较难维护。
有HystrixCommand之后:
如图示,RibbonCommand继承HystrixCommand,它有三个子类
代码语言:javascript复制public class SimpleHystrix {
private SimpleHystrixCommand simpleHystrixCommand;
public void setSimpleHystrixCommand(SimpleHystrixCommand simpleHystrixCommand) {
this.simpleHystrixCommand = simpleHystrixCommand;
}
public void call() {
simpleHystrixCommand.execute();
}
}
//SimpleHystrixRun为client
public class SimpleHystrixRun {
public static void main(String[] args) {
// 这里service为命令的实际执行者,即Receiver
RestService restService= newRestService();
//simpleHystrix为命令的请求者,即Invoker
SimpleHystrix simpleHystrix = new SimpleHystrix();
//HttpClientRibbonCommand等是具体命令, ConcreteCommand
simpleHystrix.setSimpleHystrixCommand(new HttpClientRibbonCommand(restService));
simpleHystrix.call();
HttpClientServicehttpClientService= newHttpClientService();
simpleHystrix.setSimpleHystrixCommand(new OkHttpRibbonCommand(httpClientService));
simpleHystrix.call();
OkHttpService okHttpService= newOkHttpService();
simpleHystrix.setSimpleHystrixCommand(new RestClientRibbonCommand(okHttpService));
simpleHystrix.call();
}
}
具体执行逻辑在Command中实现,如
ConcreteCommand:
代码语言:javascript复制public class HttpClientRibbonCommand implements SimpleHystrixCommand {
@Override
public void execute() {
//do things
}
}
将服务的实现封装到一个对象委托出去,由命令对象来实现具体的调用。只需要增加一个继承Command的类,然后在execute方法实现对应服务的调用以及其他操作即可,无需侵入业务代码。
java达人