概念:

  Command模式也叫命令模式 ,是行为设计模式的一种。Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数。

  命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

  主要解决:

  在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二

者之间的松耦合。这就是命令模式(Command Pattern)。

  下面,举一个小例子,但不是使用命令模式实现的

  新建一个Peddler类,是一个卖水果的小商贩

 /*
* 小商贩
*/
public class Peddler {
/*
* 卖苹果
*/
public void sailApple(){
System.out.println("卖苹果");
} /*
* 卖香蕉
*/
public void sailBanana(){
System.out.println("卖香蕉");
}
}

  再建一个客户端

 public class MainClass {
public static void main(String[] args) {
Peddler peddler = new Peddler();
peddler.sailApple();
peddler.sailBanana();
}
}

  结果:

  命令模式的应用场景

  在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法(像刚才的例子MainClass中,创建Peddler实例,再调度其中的方法)。

  但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。

  1、整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。

  2、调用前后需要对调用参数进行某些处理。

  3、调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。

  命令模式的结构

  

  命令模式的角色和职责

  1、Command:Command抽象类,定义命令的接口,声明执行的方法。。

  2、ConcreteCommand:Command的具体实现类,命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。

  3、Receiver:需要被调用的目标对象,接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。

  4、Invorker:通过Invorker执行Command对象,要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

  5、Client:创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。

 

  当然,我们的例子非常简单,用不到命令模式,我们假设操作很复杂,用命令模式改造一下

  首先,创建类对调用过程进行一个封装,先创建一个Command抽象父类

 public abstract class Command {
//包含一个Receiver的引用
private Peddler peddler; public Command(Peddler peddler) {
super();
this.peddler = peddler;
} public Peddler getPeddler() {
return peddler;
} public void setPeddler(Peddler peddler) {
this.peddler = peddler;
} public abstract void sail();
}

  接下来创建ConcreteCommand,每一个操作都要创建一个,所以我们要创建两个Apple与Banana

 /*
* Apple
*/
public class AppleCommand extends Command{ public AppleCommand(Peddler peddler) {
super(peddler);
} @Override
public void sail() {
//还可以在这句话前后做额外的处理
this.getPeddler().sailApple();
} }
 /*
* Banana
*/
public class BananaCommand extends Command{ public BananaCommand(Peddler peddler) {
super(peddler);
} @Override
public void sail() {
//还可以在这句话前后做额外的处理
this.getPeddler().sailBanana();
} }

  最后,修改MainClass

 public class MainClass {
public static void main(String[] args) {
Peddler peddler = new Peddler();
Command appleCommand = new AppleCommand(peddler);
Command bananaCommand = new BananaCommand(peddler); appleCommand.sail();
bananaCommand.sail(); }
}

  但是这样还不够好,可以看到这是直接由命令来调用sail方法的,这样不好,我们希望由专人来卖东西,就像人家请了一个服务员一样,所以我们再新建一个Invorker

public class Waiter {
private Command command; public Command getCommand() {
return command;
} public void setCommand(Command command) {
this.command = command;
} public void sail(){
command.sail();
}
}

  再修改客户端

 public class MainClass {
public static void main(String[] args) {
Peddler peddler = new Peddler();
Command appleCommand = new AppleCommand(peddler);
Command bananaCommand = new BananaCommand(peddler); Waiter waiter = new Waiter();
waiter.setCommand(appleCommand);
waiter.sail(); waiter.setCommand(bananaCommand);
waiter.sail(); }
}

  这样Client就直接与Invorker进行通话

  我们现在只能添加命令,却不能移除命令,,而且一次只能有一个命令,我们继续改造

 public class Waiter {
private Map<String,Command> commands; public Map<String, Command> getCommands() {
if(commands == null){
commands = new HashMap<String,Command>();
} return commands;
} public void setCommand(String key, Command command) {
if(commands == null){
commands = new HashMap<String,Command>();
}
commands.put(key, command);
} public void RemoveCommand(String key) {
commands.remove(key);
} public void sail(String key){
commands.get(key).sail();
}
}

  Client

 public class MainClass {
public static void main(String[] args) {
Peddler peddler = new Peddler();
Command appleCommand = new AppleCommand(peddler);
Command bananaCommand = new BananaCommand(peddler); Waiter waiter = new Waiter();
waiter.setCommand("apple", appleCommand);
waiter.setCommand("banana", bananaCommand); waiter.sail("apple");
waiter.sail("banana"); waiter.RemoveCommand("apple"); }
}

  这样,就完成了,一个命令模式的例子

  命令模式的优缺点

  优点: 1、降低了系统耦合度。

      2、新的命令可以很容易添加到系统中去。

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

java设计模式-----23、命令模式的更多相关文章

  1. 折腾Java设计模式之命令模式

    博客原文地址 折腾Java设计模式之命令模式 命令模式 wiki上的描述 Encapsulate a request as an object, thereby allowing for the pa ...

  2. Java设计模式 之 命令模式

    1      从属模式分类 行为性模式 2      命令模式意图 命令模式可将动作的请求者和动作的执行者对象中解耦. 该模式将一个行为操作发起者的请求封装到对象中,该请求由另外一个对象执行. 将动作 ...

  3. JAVA设计模式之 命令模式【Command Pattern】

    一.概述 命令模式能够将请求发送者和接收者全然解耦.发送者与接收者之间没有直接引用关系,发送请求的对象仅仅须要知道怎样发送请求,而不必知道怎样完毕请求.核心在于引入了命令类,通过命令类来减少发送者和接 ...

  4. 14.java设计模式之命令模式

    基本需求: 一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装app就可以控制对这些家电工作 这些智能家电来自不同的厂家,我们不想针对每一种家电都安装一个App分别控制,我们希望只要一个 ...

  5. java设计模式之命令模式

    学校中.生活中.社会中总是会存在一定的阶层,虽然我们很多人都不可认可阶层的存在.命令这一词也就在阶层中诞生.家长命令孩子,老师命令学生,领导命令小娄娄.这些都在我们的生活存在的东西,相信这一个模式学习 ...

  6. java设计模式之命令模式以及在java中作用

    命令模式属于对象的行为模式.命令模式又称为行动(Action)模式或交易(Transaction)模式. 命令模式把一个请求或者操作封装到一个对象中.命令模式允许系统使用不同的请求把客户端参数化,对请 ...

  7. 玉帝传美猴王上天,大闹天宫之Java设计模式:命令模式

    目录 示例 改进代码 命令模式 定义 意图 主要解决问题 何时使用 优缺点 玉帝传美猴王上天 命令模式和策略模式的区别 示例 系统需要设计一个命令行界面,用户可输入命令来执行某项功能,系统的功能会不断 ...

  8. 用Java 8 Lambda表达式实现设计模式:命令模式

    在这篇博客里,我将说明如何在使用 Java 8 Lambda表达式 的函数式编程方式 时实现 命令 设计模式 .命令模式的目标是将请求封装成一个对象,从对客户端的不同类型请求,例如队列或日志请求参数化 ...

  9. java的23中设计模式

    一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...

  10. 折腾Java设计模式之状态模式

    原文地址 折腾Java设计模式之状态模式 状态模式 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式.在状态模式中,我们创建表示各种状态的对象 ...

随机推荐

  1. MariaDB 主从同步与热备(14)

    MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可MariaDB的目的是完全兼容MySQL,包括API和命令行,MySQL由于现在闭源了,而能轻松成为MySQ ...

  2. 分布式锁实现思路及开源项目集成到springmvc并使用

    分布式锁顾名思义就是在分布式系统下的锁,而使用锁的唯一目的就是为了防止多个请求同时对某一个资源进行竞争性读写 在使用多线程时,为了让某一资源某一时刻只能有一个操作者,经常使用synchronized, ...

  3. MySQL order by的实现

      1.使用索引的已有顺序 2.filesort算法 filesort算法的执行流程     filesort相关的参数 sort_buffer_size 算法排序缓冲区的大小,线程级缓存 max_l ...

  4. 记录cacl()函数中使用scss变量不生效的问题

    问题 使用cacl()动态计算元素的高度,运算中包含一个scss变量.如下: height: calc(100% - $ws-header-height); 在浏览器中发现并没有达到预期效果,scss ...

  5. mongodb 初学 意外 连接服务器异常(Connection refused)

    啦啦啦 这种情况 root@localhost:/# mongo MongoDB shell version: connecting to: test --31T07:: W NETWORK [thr ...

  6. 【sping揭秘】3、Spring容器中bean默认是保持一个实例

    Spring容器中bean默认是保持一个实例 这里做一个测试,基础代码 package cn.cutter.start.provider; import org.springframework.con ...

  7. Service Fabric学习-从helloworld开始(无状态服务)

    原先做服务器程序, 都是部署在xx云上, 也没理解云是个啥, 不就是个服务器(虚拟机)租赁商吗? 好吧, 其实这个是IaaS, 而接下来要学习的ServiceFabric(以下简称SF)是PaaS. ...

  8. 剑指offer二十之包含min函数的栈

    一.题目 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数. 二.思路 用一个栈dataStack保存数据,用另外一个栈minStack保存依次入栈最小的数.每次元素存入minSt ...

  9. Identity Server4学习系列四之用户名密码获得访问令牌

    1.简介 Identity Server4支持用户名密码模式,允许调用客户端使用用户名密码来获得访问Api资源(遵循Auth 2.0协议)的Access Token,MS可能考虑兼容老的系统,实现了这 ...

  10. 微信小程序交流群,欢迎加入,其中微信小程序开发群、Jenkins开发群是有问必答群

    微信小程序开发,请加群511389428,511389428 有问必答群:React开发,请加群523838207:523838207Jenkins开发,请加群155799363,155799363  ...