设计模式详解——命令、代理、策略模式
前言
今天我们主要来看三种设计模式,他们分别是命令模式、代理模式和策略模式。废话少说,下面我们直接开始吧!
设计模式
命令模式
命令模式简单来说,就是将一组操作整合成一个通用的命令,然后通过一个通用的执行器来执行的一种设计模式,这种设计模式也是为了更好地实现代码的解耦。
这种设计模式就类似于一个遥控器,遥控器上的每一个按钮都对应一个命令,我们不需要关心命令内部执行流程,只需要按下(执行)这个按钮,然后相关命令就会被执行。
这么说还是有点抽象,下面我们通过一个简单的示例来演示下命令模式的用法。
代码都很简单,对于代码这里就不详细说明了,各位小伙伴要关注的是代码的设计,以及他所达到的解耦效果。
要执行命令的对象
public class Light {
public void on() {
System.out.println("开灯了");
}
public void off() {
System.out.println("关灯了");
}
}
命令接口
public interface Command {
void execute();
}
命令实现
关灯命令
public class LightOffCommand implements Command {
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
}
开灯命令
public class LightOnCommand implements Command {
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
命令执行(控制层)
public class SimpleRemoteControl {
Command command;
public SimpleRemoteControl() {
}
public void setCommand(Command command) {
this.command = command;
}
public void buttonWasPressed() {
command.execute();
}
}
测试代码
public class CommandTest {
@Test
public void testCommand() {
// 创建控制器实例
SimpleRemoteControl control = new SimpleRemoteControl();
// 创建命令执行对象实例
Light light = new Light();
// 创建命令实例
LightOnCommand onCommand = new LightOnCommand(light);
LightOffCommand offCommand = new LightOffCommand(light);
// 开灯
// 设置命令
control.setCommand(onCommand);
// 执行命令
control.buttonWasPressed();
// 关灯操作
control.setCommand(offCommand);
control.buttonWasPressed();
}
}
运行结果
如果各位小伙伴如果用过struts
框架的话,应该对这个设计模式不陌生,因为在struts
的业务控制层中,命令模式被广泛应用。
优点
关于命令模式的好处,想必各位小伙伴都已经看出来了:它实现了控制层与具体对象之间的耦合关系,当我们具体的业务对象发生变化时,我们只需要调整其所对应的命令实现类即可,而不需要调整控制层相关代码,即提高了系统的可扩展性,又保证了它的健壮性,是不是美滋滋呢!
要点
命令模式将发出请求的对象和执行请求的对象解耦 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作 调用者通过调用命令对象的 execute()
(方法名可以自己起)发出请求,这会使得接受者的动作被调用调用者可以接受命令当做参数,甚至在运行时动态地进行 命令可以支持撤销,做法是实现一个 undo()
方法(也可以自定义)来回到execute()
被执行前的状态宏命令是命令的一种简单延伸,允许调用多个命令,宏方法也可以支持撤销。 实际操作时,很常见使用“聪明”命令对象,也就是直接实现了请求,而不是将工作委托给接收者 命令也可以用来实现日志和事务系统
代理模式
我发现关于代理模式的内容还是比较多的,考虑到篇幅和时间,我们今天先说下它的要点,同时由于之前我在分享手写rpc
框架内容的时候已经展示过动态代理的相关用法了,所以今天暂时先不展开讲,等后面把这块内容彻底梳理清楚之后,我们再来继续分享。
关于手写rpc
框架中动态代理的内容,可以移步到这里看下:
要点
代理模式为另一个对象提供代表,以便控制客户对对象的访问,管理访问的方式有许多种 远程代理管理客户和远程对象之间的交互 虚拟代理控制访问实例化开销大的对象 保护代理基于调用者控制对象方法的访问 代理模式有许多变体,例如:缓存代理、同步代理、防火墙代理和写入时复制代理 代理在结构上类似装饰者,但是目的不同。装饰是模式为对象加上行为,而代理则是控制访问 java
内置的代理支持,可以根据需要建立动态代理,并将所有调用分配到所选的处理器和其他的包装者一样,代理会造成你的设计中类的数目增加。
策略模式
关于策略模式,我们前几天刚分享了一篇与之相关的应用内容,各位小伙伴可以回顾下:
策略模式主要是为了优化代码中的逻辑问题,特别是在有多种算法相似的情况下,使用 if...else
所带来的复杂和难以维护的问题。
策略这个词,我们在日常生活中也会经常用到,意思也基本上一致,这里的策略模式就是我们做事策略思维在软件开发中的应用。
应用实例
诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 JAVA AWT
中的LayoutManager
使用场景
如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
一个系统需要动态地在几种算法中选择一种。
如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
实例代码
下面是数字加减的策略模式实现,各位小伙伴可以试着从代码中理解下策略模式。
策略接口
public interface Strategy {
int doOperation(int num1, int num2);
}
加法策略实现
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
减法策略实现
public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
策略控制器
public class StrategyControl {
private Strategy strategy;
public StrategyControl(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
测试代码
public class StrategyPatternDemo {
public static void main(String[] args) {
StrategyControl control = new StrategyControl(new OperationAdd());
System.out.println("10 + 5 = " + control.executeStrategy(10, 5));
control = new StrategyControl(new OperationSubtract());
System.out.println("10 - 5 = " + control.executeStrategy(10, 5));
}
}
优点
策略模式的优点也很明显,当我们的算法策略发生变动时,我们只需要增加新的策略即可,而不需要修改策略实现之外的代码,代码的可扩展性又得到了极大的提升。
总结
好了,关于这三种设计模式,我们暂时就先说这么多。
从我们总结的设计模式的优点来看,基本上所有的设计模式,都是为了提升我们系统的可扩张性,同时降低系统的耦合性,而且一定程度上减少了重复代码,当然也是我们要学习和应用设计模式的意义。
最后,大家需要着重关注的是策略模式和命令模式,这两种设计模式是我们在业务开发中最可能能用到的,特别是策略模式,至于代理模式,我目前能想到的就是框架开发了,其他的我暂时还真想不到。
- END -