示例

系统需要设计一个命令行界面,用户可输入命令来执行某项功能,系统的功能会不断增加,命令也会不断的增加

如何将一项一项的功能加入到这个命令行界面?

如何让命令行程序写好后,不因功能的添加而修改,又可以灵活的加入命令和功能?

下面以奶茶店售卖奶茶为例:

public class MashedTaroMilk {

    public void build() {
System.out.println("奶茶师傅制作芋泥啵啵奶茶。。。");
}
}
public class StrawBerryMilk {
public void build() {
System.out.println("奶茶师傅制作草莓奶茶。。。");
}
}

服务员类:负责接待顾客售卖奶茶

public class Waiter {
public void receiver(String command) {
System.out.println("您选择了:" + command);
switch (command) {
case "芋泥啵啵奶茶" :
new MashedTaroMilk().build();
break;
case "草莓奶茶" :
new StrawBerryMilk().build();
break;
default :
System.out.println("您点的奶茶本店没有。。。");
break;
}
} public void showMenu() {
System.out.println("您好,本店有以下奶茶:");
System.out.println("\t芋泥啵啵奶茶");
System.out.println("\t草莓奶茶");
}
}

测试类:

public class Client {

    public static void main(String[] args) {
waiter();
} public static void waiter() {
Waiter waiter = new Waiter();
waiter.showMenu();
Scanner scanner = new Scanner(System.in);
System.out.println("请选择:");
String chooseMilk = scanner.nextLine();
waiter.receiver(chooseMilk);
scanner.close();
}
}



现在如果奶茶增加了呢,需要对服务员类中的switch语句进行修改,但是又不想修改,该怎么做呢

改进代码

定义一个制作奶茶的接口,所有的奶茶实现它:

public interface Command {
/** 制作奶茶接口 */
void build();
}

实现类:

public class AppleMilk implements Command {
@Override
public void build() {
System.out.println("开始制作苹果奶茶。。。");
}
}
public class PlainMilk implements Command {
@Override
public void build() {
System.out.println("开始制作原味奶茶。。。");
}
}

现在又招了一个女服务员,负责接待:

public class Waitress {

    private Map<String, Command> map = new HashMap<>();

    public void addMilk(String name, Command command) {
map.put(name, command);
} public void receiver(String command) {
System.out.println("您选择了:" + command);
Command command1 = map.get(command);
if (command1 != null) {
command1.build();
} else {
System.out.println("您点的奶茶本店没有。。。");
}
} public void showMenu() {
System.out.println("您好,本店有以下奶茶:");
map.keySet().forEach((item)->{
System.out.println("\t" + item);
});
}
}

测试类:

public class Client {

    public static void main(String[] args) {
waitress();
} public static void waitress() {
Waitress waitress = new Waitress();
waitress.addMilk("苹果奶茶", new AppleMilk());
waitress.addMilk("原味奶茶", new PlainMilk());
waitress.showMenu();
Scanner scanner = new Scanner(System.in);
System.out.println("请选择:");
String chooseMilk = scanner.nextLine();
waitress.receiver(chooseMilk);
scanner.close();
}
}



上面改进之后,每增加一个新的奶茶,只需要实现接口即可

命令模式

定义

以命令的方式,解耦调用者和功能的具体实现者,降低了系统的耦合度,提高了灵活性

意图

将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化

主要解决问题

在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适

何时使用

在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合

优缺点

优点:

  1. 降低了系统的耦合度
  2. 提高了灵活性

缺点:

使用命令模式可能会导致某些系统有过多的具体命令类

类图:



涉及的角色:

  1. 客户(Client)角色:创建了一个具体命令(ConcreteCommand)对象并确定其接收者
  2. 命令(Command)角色:声明了一个给所有具体命令类的抽象接口,通常由接口或者抽象类实现
  3. 具体命令(ConcreteCommand)角色:定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作,execute()方法通常叫做执行方法
  4. 请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法
  5. 接收者(Receiver)角色:负责具体实施和执行一个请求,任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法

对应的类如下:

Client类:

public class Client {

    public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker(command);
invoker.action();
}
}

Command接口:

public interface Command {

    /** 执行方法 */
void execute();
}

ConcreteComman实现类:

public class ConcreteCommand implements Command {

    private Receiver receiver;

    public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
} @Override
public void execute() {
System.out.println("do something......");
receiver.action();
}
}

Invoker类:

public class Invoker {

    private Command command;

    public Invoker(Command command) {
this.command = command;
} /** 行动方法 */
public void action() {
command.execute();
}
}

Receiver类:

public class Receiver {

    public Receiver() {

    }

    /** 行动方法 */
public void action() { }
}

玉帝传美猴王上天

在美猴王大闹天宫之前,玉帝命令太白金星召美猴王上天,玉帝的这一道旨意就是一个命令,而太白金星则是负责将圣旨传到,具体的执行者则是美猴王:

抽象接口,所有的圣旨都需要实现它:

public interface ImperialEdictCommand {

    /** 抽象圣旨,具体圣旨都必须具备的接口 */
void command();
}

具体的命令,即召美猴王上天这一个具体的圣旨:

public class SkyReportsConcreteCommand implements ImperialEdictCommand {

    private MonkeyKingReceiver receiver;

    public SkyReportsConcreteCommand(MonkeyKingReceiver receiver) {
this.receiver = receiver;
} @Override
public void command() {
System.out.println("宣美猴王孙悟空上天报道!");
receiver.action();
}
}

玉皇大帝,颁布圣旨:

public class TheJadeEmperorClient {

    public static void main(String[] args) {
System.out.println("玉皇大帝颁布一道圣旨,宣美猴王上天报道!");
MonkeyKingReceiver receiver = new MonkeyKingReceiver();
ImperialEdictCommand command = new SkyReportsConcreteCommand(receiver);
GreatWhitePlanetInvoker invoker = new GreatWhitePlanetInvoker();
invoker.setCommand(command);
invoker.action();
}
}

太白金星负责把旨意传达给美猴王:

public class GreatWhitePlanetInvoker {

    private ImperialEdictCommand command;

    public void setCommand(ImperialEdictCommand command) {
this.command = command;
} /** 请求者太白金星调用此方法,要求美猴王上天 */
public void action() {
System.out.println("太白金星传玉帝圣旨!");
command.command();
}
}

具体的执行者,就是美猴王:

public class MonkeyKingReceiver {

    public MonkeyKingReceiver() {

    }
public void action() {
System.out.println("美猴王孙悟空上天,大闹天宫!");
}
}



类图:

命令模式和策略模式的区别

命令模式的结构如下:



策略模式的结构如下:



策略模式:侧重的是一个行为的多个算法实现,可互换算法,比如优惠活动满减和打折都是算法,可以选择其中一个来买买买

命令模式:侧重的是为多个行为提供灵活的执行方式,比如上面的奶茶,每个顾客购买奶茶的命令都是一个行为,而不同的奶茶制作方式不一样,则就需要灵活的去制作奶茶

玉帝传美猴王上天,大闹天宫之Java设计模式:命令模式的更多相关文章

  1. 【设计模式】Java设计模式 - 命令模式

    Java设计模式 - 命令模式 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! 目录 Ja ...

  2. Java设计模式-命令模式(Command)

    命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行.这个过程好在,三者相互解耦,任何一方都不用去依赖其 ...

  3. JAVA 设计模式 命令模式

    用途 命令模式 (Command) 将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化:对请求排队或请求日志,以及支持可撤销的操作. 命令模式是一种行为型模式. 结构

  4. JAVA设计模式---命令模式

    1.定义: 将“请求”封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象,命令模式也支持可撤销的操作.命令可以用来实现日志和事务系统. 2.实例: 1)需求:设计一个家电遥控器的API,遥控 ...

  5. Java设计模式—命令模式

    命令模式是一个高内聚的模式. 定义如下:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 通用类图如下: 角色说明: ● Re ...

  6. Java设计模式の命令模式

    意图: 将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化:对请求排队或记录日志,以及支持可撤销的操作 动机: 将”发出请求的对象”和”接收与执行这些请求的对象”分隔开来. 效果: 1).c ...

  7. Java设计模式-代理模式之动态代理(附源代码分析)

    Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...

  8. 【设计模式】Java设计模式 - 桥接模式

    [设计模式]Java设计模式 - 桥接模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起 ...

  9. Java设计模式——组合模式

    JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...

随机推荐

  1. MFC多文档程序启动无子窗口的实现

    刚学MFC的我们,肯定会从一个基本MFC程序开始. 而VC++6.0的MFC基础类提供了三种创建方式:单文档.多文档.对话框. 当我们创建多文档应用程序的时候,会自动启动一个子窗口. 在我们平时使用软 ...

  2. el-input输入框的readonly属性

    readonly属性是Boolean类型,默认值为false.readonly值为true表示只读. <el-col :span="12"> <el-form-i ...

  3. pwn篇:攻防世界进阶welpwn,LibcSearcher使用

    攻防世界welpwn (搬运一篇自己在CSDN写的帖子) 链接:https://blog.csdn.net/weixin_44644249/article/details/113781356 这题主要 ...

  4. Spring Boot集成Springfox Swagger3和简单应用

    摘要:Springfox Swagger可以动态生成 API 接口供前后端进行交互和在线调试接口,Spring Boot 框架是目前非常流行的微服务框架,所以,在Spring Boot 项目中集成Sp ...

  5. 基于角色访问控制RBAC权限模型的动态资源访问权限管理实现

    RBAC权限模型(Role-Based Access Control) 前面主要介绍了元数据管理和业务数据的处理,通常一个系统都会有多个用户,不同用户具有不同的权限,本文主要介绍基于RBAC动态权限管 ...

  6. go中errgroup源码解读

    errgroup 前言 如何使用 实现原理 WithContext Go Wait 错误的使用 总结 errgroup 前言 来看下errgroup的实现 如何使用 func main() { var ...

  7. 确保某个BeanDefinitionRegistryPostProcessor Bean被最后执行的几种实现方式

    目录 一.事出有因 二.解决方案困境 三.柳暗花明,终级解决方案 第一种实现方案 第二种实现方案 第三种实现方案 四.引发的思考 一.事出有因 ​ 最近有一个场景,因同一个项目中不同JAR包依赖同一个 ...

  8. Java 并发编程之 Condition 接口

    本文部分摘自<Java 并发编程的艺术> 概述 任意一个 Java 对象,都拥有一个监视器方法,主要包括 wait().wait(long timeout).notify() 以及 not ...

  9. 目标检测入门论文YOLOV1精读以及pytorch源码复现(yolov1)

    结果展示 其中绿线是我绘制的图像划分网格. 这里的loss是我训练的 0.77 ,由于损失函数是我自己写的,所以可能跟大家的不太一样,这个不重要,重要的是学习思路. 重点提示 yolov1是一个目标检 ...

  10. golang 微服务以及相关web框架

    golang 中国gocn golang Applicable to all database connection pools xorm是一个简单而强大的Go语言ORM库,通过它可以使数据库操作非常 ...