命令模式
命令模式(Command Pattern)是一种数据驱动的设计模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
介绍
- 意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
- 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
- 何时使用:当需要先将一个函数登记上,然后再以后调用此函数时,就需要使用命令模式,其实这就是回调函数。
- 优点:1.类间解耦:调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用Command 抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。2.可扩展性:Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严 重的代码耦合。3.命令模式结合其他模式会更优秀:命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少 Command子类的膨胀问题。
- 缺点:命令模式也是有缺点的,请看Command的子类:如果有N个命令,问题就出来 了,Command的子类就可不是几个,而是N个,这个类膨胀得非常大,这个就需要读者在项 目中慎重考虑使用。
命令模式结构示意图:
java
我们首先创建作为命令的接口 Order,然后创建作为请求的 Stock 类。实体命令类 BuyStock 和 SellStock,实现了 Order 接口,将执行实际的命令处理。创建作为调用对象的类 Broker,它接受订单并能下订单。
Broker 对象使用命令模式,基于命令的类型确定哪个对象执行哪个命令。CommandPatternDemo 类使用 Broker 类来演示命令模式。
步骤 1
创建一个命令接口。
Order.java
public interface Order { void execute(); }
步骤 2
创建一个请求类。
Stock.java
public class Stock { private String name = "ABC"; private int quantity = 10; 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
public class BuyStock implements Order { private Stock abcStock; public BuyStock(Stock abcStock){ this.abcStock = abcStock; } public void execute() { abcStock.buy(); } }
SellStock.java
public class SellStock implements Order { private Stock abcStock; public SellStock(Stock abcStock){ this.abcStock = abcStock; } public void execute() { abcStock.sell(); } }
步骤 4
创建命令调用类。
Broker.java
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(); } }
步骤 5
使用 Broker 类来接受并执行命令。
CommandPatternDemo.java
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(); } }
步骤 6
执行程序,输出结果:
Stock [ Name: ABC, Quantity: 10 ] bought Stock [ Name: ABC, Quantity: 10 ] sold
rust
trait Order { fn execute(&self); } #[derive(Clone)] struct Stock{ name:String, quantity:i32, } impl Stock { fn buy(&self) { println!("Stock [ Name : {} Quantity: {}] bought",self.name,self.quantity); } fn sell(&self) { println!("Stock [ Name : {} Quantity: {}] sold",self.name,self.quantity); } fn new()->Stock{ Stock{ name:"ABC".to_owned(), quantity:10 } } } // 创建命令实体 struct BuyStock { abc_stock:Stock } impl Order for BuyStock { fn execute(&self) { self.abc_stock.buy(); } } struct SellStock { abc_stock:Stock } impl Order for SellStock { fn execute(&self) { self.abc_stock.sell(); } } // 创建命令调用类。 struct Broker{ order_list:Vec<Box<dyn Order>> } impl Broker { fn take_order(&mut self,order:impl Order+ 'static){ self.order_list.push(Box::new(order)); } fn place_orders(&self){ self.order_list.iter().for_each(|f|f.execute()); } fn new()->Broker { Broker{ order_list:vec![] } } } fn main(){ let stock=Stock::new(); let buy=BuyStock{abc_stock:stock.clone()}; let sell=SellStock{abc_stock:stock.clone()}; let mut broker=Broker::new(); broker.take_order(buy); broker.take_order(sell); broker.place_orders(); }
rust仓库
https://github.com/onenewcode/design.git
本教程项目在bin文件夹下的command.rs文件中