[设计模式/Java] 设计模式之命令模式【26】
概述:命令模式 ∈ 行为型模式模式定义
[*]命令模式(Command Pattern)是一种数据驱动的设计模式
[*]属于行为型模式
[*]命令模式将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
[*]主要解决的问题
解决在软件系统中请求者和执行者之间的紧耦合问题,特别是在需要对行为进行记录、撤销/重做或事务处理等场景。
模式的组成
[*]【命令】(Command):
定义了执行操作的接口,通常包含一个 execute 方法,用于调用具体的操作。
[*]具体命令(ConcreteCommand):
实现了命令接口,负责执行具体的操作。
它通常包含了对接收者的引用,通过调用接收者的execute方法来完成请求的处理。
[*]【接收者】(Receiver):
知道如何执行与请求相关的操作,实际执行命令的对象。
[*]【调用者/请求者】(Invoker):
发送命令的对象,它包含了一个命令对象并能触发命令的执行。
调用者并不直接处理请求,而是通过将请求传递给命令对象来实现。
[*]客户端(Client):
创建具体命令对象,并设置其接收者,将命令对象交给调用者执行。
实现方式
[*]定义命令接口:所有命令必须实现的接口。
[*]创建具体命令:实现命令接口的具体类,包含执行请求的方法。
[*]调用者:持有命令对象并触发命令的执行。
[*]接收者:实际执行命令的对象。
模式特点
优点
[*]降低耦合度:请求者和执行者之间的耦合度降低。
[*]易于扩展:新命令可以很容易地添加到系统中。
缺点
[*]过多命令类:系统可能会有过多的具体命令类,增加系统的复杂度。
使用建议
[*]如果系统需要支持命令的撤销(Undo)和恢复(Redo)操作,命令模式也是一个合适的选择。
[*]在GUI中,每个按钮或菜单项可以视为一条命令。
[*]在需要模拟命令行操作的场景中使用命令模式。
适用场景
[*]使用时机:当需要先将一个函数【登记】上,然后再以后【调用】此函数时,就需要使用命令模式
有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。
此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。
[*]例子:拿订餐来说,客人需要向厨师发送请求,但是完全不知道这些厨师的名字和联系方式,也不知道厨师炒菜的方式和步骤。
命令模式把客人订餐的请求封装成 command 对象,也就是订餐中的订单对象。
这个对象可以在程序中被四处传递,就像订单可以从服务员手中传到厨师的手中。
这样一来,客人不需要知道厨师的名字,从而解开了请求调用者和请求接收者之间的耦合关系
案例实践
CASE 命令模式的实现
Receiver
[*]Receiver类 : 知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接受者
public class Receiver {
public void Action() {
Console.WriteLine("执行请求!");
}
}Command
[*]Command类 : 用来声明执行操作的接口
abstract class Command {
protected Receiver receiver;
public Command(Receiver receiver) {
this.receiver = receiver;
}
abstract public void Execute();
}ConcreteCommand
[*]ConcreteCommand类,将一个接受者对象绑定于一个动作,调用接受者相应的操作,以实现Execute。
class ConcreteCommand : Command {
public ConcreteCommand(Receiver receiver) : base(receiver) {
}
public override void Execute() {
receiver.Action();
}
}Invoker
[*]Invoker类: 要求该命令执行这个请求
class Invoker {
private Command command;
public void SetCommand(Command command) {
this.command = command;
}
public void ExecuteCommand() {
command.Execute();
}
}Client
static void Main(string[] args) {
Receiver r = new Receiver();//接收者,如:厨师
Command c = new ConcreteCommand(r);//创建具体命令,如:点菜(麻婆豆腐)
Invoker i = new Invoker();//调用者,如:客户小美
i.SetCommand(c);//设置具体命令
i.ExecuteCommand();//执行命令
Console.Read();
}CASE 股票订单的买入、卖出
[*]我们首先创建作为命令的接口 Order,然后创建作为请求的 Stock 类。
[*]实体命令类 BuyStock 和 SellStock,实现了 Order 接口,将执行实际的命令处理。
[*]创建作为调用对象的类 Broker,它接受订单并能下订单。
[*]Broker 对象使用命令模式,基于命令的类型确定哪个对象执行哪个命令。
[*]CommandPatternDemo 类使用 Broker 类来演示命令模式。
Order : 命令接口
public interface Order {
void execute();
}Stock : 请求类
public class Stock {
private String name = "ABC";
private int quantity = 100;
public void buy(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] bought");
}
public void sell(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] sold");
}
}BuyStock / SellStock : 具体的请求类
创建实现了 Order 接口的实体类。
[*]BuyStock 买入股票
public class BuyStock implements Order {
private Stock abcStock;
public BuyStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.buy();
}
}
[*]SellStock 售出股票
public class SellStock implements Order {
private Stock abcStock;
public SellStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.sell();
}
}Broker : 命令调用类
创建命令调用类。
import java.util.ArrayList;
import java.util.List;
public class Broker {
private List<Order> orderList = new ArrayList<Order>(); //订单列表
public void takeOrder(Order order){//接收订单
orderList.add(order);
}
public void placeOrders(){//下订单
for (Order order : orderList) {
order.execute();
}
orderList.clear();
}
}Client
使用 Broker 类来接受并执行命令
[*]CommandPatternDemo
public class CommandPatternDemo {
public static void main(String[] args) {
Stock abcStock = new Stock();
BuyStock buyStockOrder = new BuyStock(abcStock);
SellStock sellStockOrder = new SellStock(abcStock);
Broker broker = new Broker();
broker.takeOrder(buyStockOrder);
broker.takeOrder(sellStockOrder);
broker.placeOrders();
}
}out
Stock [ Name: ABC, Quantity: 100 ] bought
Stock [ Name: ABC, Quantity: 100 ] soldY 推荐文献
[*]设计模式之总述 - 博客园/千千寰宇
X 参考文献
[*]命令模式 - 菜鸟教程
[*]深入理解设计模式(十):命令模式 - 博客园 【推荐】
本文作者: 千千寰宇
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]