前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【设计模式】行为型模式-第 3 章第 2 讲【命令模式】

【设计模式】行为型模式-第 3 章第 2 讲【命令模式】

作者头像
跟着飞哥学编程
发布2022-12-02 15:52:10
2550
发布2022-12-02 15:52:10
举报

目录

1、命令模式定义

2、为何要用命令模式?

3、实现

3.1、命令模式的通用类图,如图 1-1

3.2、具体实现案例

 4、适用情况和示例

5、命令模式的优缺点

5.1、优点

5.2、缺点

6、结语


1、命令模式定义

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

在面向对象编程当中,一个很重要的事情是设计能够使得代码松耦合。举个例子,我们需要开发一个复杂的程序,用来绘制诸如点、线、线段、圆、矩形等许多图形。

为了让代码能够实现所有种类的形状,我们需要实现很多操作来处理菜单操作。

为了让程序可维护,我们需要创建一个统一的方法来定义所有的命令,这样做便能够将所有实现细节隐藏在程序之中(这个程序实际上就是客户端)。

2、为何要用命令模式?

命令模式能够做到:

  • 提供一个统一的方法来封装命令和其所需要的参数来执行一个动作。
  • 允许处理命令,例如将命令存储在队列中。

注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式。 

3、实现

3.1、命令模式的通用类图,如图 1-1

 图 1-1

 上面的类图中包括以下元素:

Command(命令类):这是表示命令封装的抽象类。它声明了执行的抽象方法,该方法应该由所有具体命令实现。

ConcreteCommand(具体命令类):这是命令的实际实现。它必须执行命令并处理与每个具体命令相关的参数。它将命令委托给接收者。

Receiver(接收者):这是负责执行与命令关联的操作的类。

Invoker(调用者):这是触发命令的类。通常是外部事件,例如用户操作。

Client(客户端):这是实例化具体命令对象及其接收者的实际类。

3.2、具体实现案例

我们首先创建作为命令的接口 Order,然后创建作为请求的 Stock 类。具体命令类 BuyStock 和 SellStock,实现了 Order 接口,将执行实际的命令处理。创建作为调用对象的类 Broker(触发命令的类),它接受订单并能下订单。

Broker 对象使用命令模式,基于命令的类型确定哪个对象执行哪个命令。CommandPatternDemo 类使用 Broker 类来演示命令模式。

 1)先创建作为命令的接口 Order.java

Order.java

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.commandpattern;
/**
 * @Date 2022年10月6日
 * @author zhaoYanFei
 * 订单接口(Command(命令类))
 *
 */
public interface Order {

	void execute();
	
}

 2)创建一个请求类 Stock.java

Stock.java

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.commandpattern;


/**
 * Stock 请求类
 * @Date 2022年10月6日
 * @author zhaoYanFei
 */
public class Stock {
	  
	   private String name = "笔记本";
	   private int quantity = 3;
	 
	   public void buy(){
	      System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] bought");
	   }
	   public void sell(){
	      System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] sold");
	   }
}

3)创建实现了 Order 接口的具体命令类

BuyStock.java

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.commandpattern;


/**
 * BuyStock 具体执行命令的类
 * @Date 2022年10月6日
 * @author zhaoYanFei
 */
public class BuyStock implements Order {

	private Stock stock;
	
	@Override
	public void execute() {
		// TODO Auto-generated method stub
		stock.buy();
	}
	
	public BuyStock(Stock stock){
		this.stock = stock;
    }
}

SellStock.java

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.commandpattern;


/**
 * SellStock 具体执行命令的类
 * @Date 2022年10月6日
 * @author zhaoYanFei
 */
public class SellStock implements Order {

	private Stock stock;
	
	@Override
	public void execute() {
		// TODO Auto-generated method stub
		stock.sell();
	}
	
	public SellStock(Stock stock){
		this.stock = stock;
    }
}

4)创建命令调用类 Broker.java ,将命令存放在任务队列中。

Broker.java 

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.commandpattern;

import java.util.ArrayList;
import java.util.List;


/**
 * Broker 命令调用类
 * @Date 2022年10月6日
 * @author zhaoYanFei
 *
 */
public class Broker {

	private List<Order> orderList = new ArrayList<Order>();
	
	//添加命令到队列中
	public void addCommand(Order order) {
		orderList.add(order);
	}
	
	//执行命令集合
	public void executeCommand() {
		for (Order order : orderList) {
			order.execute();
		}
		//清空任务队列
		orderList.clear();
	}
}

5)创建客户端调用测试类 CommandPatternDemo.java

使用 Broker 类来接受并执行命令。 

CommandPatternDemo.java

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.commandpattern;


/**
 * CommandPatternDemo 客户端调用测试类
 * @Date 2022年10月6日
 * @author zhaoYanFei
 *
 */
public class CommandPatternDemo {

	public static void main(String[] args) {
		Stock stock = new Stock();
		
		BuyStock buyStock = new BuyStock(stock);
		SellStock sellStock = new SellStock(stock);
		
		Broker broker = new Broker();
		broker.addCommand(buyStock);
		broker.addCommand(sellStock);
		broker.executeCommand();
	}
	
}

执行结果如下:

 4、适用情况和示例

Undo/Redo operation(撤销 / 重做操作):命令模式允许我们将命令对象存储在队列中。这样就可以实现撤销和重做操作。

Composite command (组合命令) :复杂命令可以使用组合模式由简单命令组成,并按顺序运行。通过这种方式,我们可以以面向对象的方式构建宏。

The asynchronous method invocation(异步方法调用):命令模式用于多线程应用程序。命令对象可以在后台以单独的线程执行。java.lang.Runnable 是一个命令接口。

下面代码中,Runnable 接口充当命令接口,由 RunnableThread 具体实现执行命令

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.commandpattern;


public class RunnableThread implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("the command implementation code");
	}

}

客户端调用命令启动新线程:

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.commandpattern;

public class ClientThread {

	public static void main(String[] args) {
		RunnableThread runnableThread = new RunnableThread();
		Thread thread = new Thread(runnableThread);
		thread.start();
	}
	
}

 执行程序,输出结果如下:

5、命令模式的优缺点

5.1、优点

1、降低了系统耦合度。

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

5.2、缺点

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

6、结语

 回顾一下,这篇文章的内容

命令模式中的4个角色:

  1. 接收者角色(Receiver):负责具体执行一个请求
  2. 命令角色(ICommand):定义需要执行的所有命令行为
  3. 具体的命令角色(ConcreteCommand):内部维护一个Receiver
  4. 请求者角色(Invoker):接收客户端的命令,并执行命令

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

 下一节,我会分享行为型模式中的解释器模式。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-10-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、命令模式定义
  • 2、为何要用命令模式?
  • 3、实现
    • 3.1、命令模式的通用类图,如图 1-1
      • 3.2、具体实现案例
      •  4、适用情况和示例
      • 5、命令模式的优缺点
        • 5.1、优点
          • 5.2、缺点
          • 6、结语
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档