前言
命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,从而解耦的执行相关的操作。命令模式也叫行动模式或者交易模式;使用命令模式的优点就是在新加入命令的时候很容易扩展,而且如果要存储命令执行顺序也很容易维护一个这样的队列,很容易实现命令的撤销与恢复,大多数优点都基于维护一个队列。
角色扮演
Receiver:具体执行请求操作类,其具体方法叫行动方法。
Command:声明了一个命令类的抽象接口。
ConcreteCommand:定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。execute()方法通常叫做执行方法。
Invoker:负责调用命令对象执行请求,相关的方法叫做行动方法。
Client:调用类,创建相关执行类和接受类。
适用场景
当需要对行事务操作优先考虑命令模式;系统需要调用者和接收者不直接交互时优先选择命令模式;需要在不同时间指定请求、请求排队和执行请求时;系统需要将一组操作组合在一起时。
Demo
对于我在写demo的时候就总觉得这个模式在使用中完全可以直接调用Receiver的相关方法就能够完成,但是这样做有什么不一样呢,一方面提高了代码阅读性,记住开发的原则是对修改关闭对扩展开发,这样使用如果后期别人维护该项目会方便很多,咱们开发可是团队作业,demo我就抽象出一个存取款模型,满足4个功能:存钱、取钱、查余额、查账单。
Receiver:
package com.demo.command;
import java.util.ArrayList;
import java.util.List;
/**
* Created by italkbb on 2017/12/22.
*/
public class Account {
private int totalAmount = 0;
// 简单的维护一个账单流水
private List<Integer> moperations = new ArrayList<>();
/**
* 存钱
* @param money 存钱金额
*/
public void accountIn(int money){
this.totalAmount += money;
moperations.add(money);
}
/**
* 取钱
* @param money 取钱金额
*/
public void accountOut(int money){
totalAmount -= money;
moperations.add(money);
}
/**
* 查询余额
* @return
*/
public int getAccountAmout(){
return totalAmount;
}
/**
* 获取账单流水
* @return
*/
public String getBill(){
String simpleBill = new String();
for (Integer money:moperations){
if(money < 0){
simpleBill += "取钱:" + money + "\n";
}else {
simpleBill += "存钱:" + money + "\n";
}
}
return simpleBill;
}
}
Command:
package com.demo.command;
/**
* Created by italkbb on 2017/12/22.
*/
public abstract class Command {
// 账户类
protected Account account;
public Command(Account account)
{
this.account = account;
}
// 抽象命令执行方法
public abstract void action();
}
然后定义ConcreteCommand类,这里只定义存钱和取钱:
ConcreteCommand存钱:
package com.demo.command;
/**
* Created by italkbb on 2017/12/22.
*/
public class AccountInCommand extends Command {
private int money;
public AccountInCommand(Account account,int money){
super(account);
this.money = money;
}
/**
* 存钱操作
*/
@Override
public void action() {
account.accountIn(money);
}
}
ConcreteCommand取钱:
package com.demo.command;
/**
* Created by italkbb on 2017/12/22.
*/
public class AccountOutCommand extends Command {
private int money;
public AccountOutCommand(Account account,int money){
super(account);
this.money = money;
}
/**
* 取钱操作
*/
@Override
public void action() {
account.accountOut(money);
}
}
然后是具体的Invoker类:
Invoker:
package com.demo.command;
/**
* Created by italkbb on 2017/12/22.
*/
public class Invoker {
private Command command;
public void setCommand(Command command){
this.command = command;
}
/**
* 具体执行类
*/
public void executeCommand(){
command.action();
}
}
最后是调用类,这里就是Activity了
Client:
package com.demo.command;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import teltplay.example.com.kotlindemo.R;
/**
* Created by italkbb on 2017/12/22.
*/
public class CommandActivity extends AppCompatActivity {
private Account account = null;
private TextView mAccountDisplay = null;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_command);
mAccountDisplay = findViewById(R.id.account_display);
// 创建银行帐号
account = new Account();
// 存钱
findViewById(R.id.account_in).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 存200块钱
Command commandIn = new AccountInCommand(account,200);
// 创建一个调度者
Invoker invoker = new Invoker();
// 告诉调度者我要存钱
invoker.setCommand(commandIn);
// 干活
invoker.executeCommand();
}
});
// 取钱
findViewById(R.id.account_out).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 取200块钱
Command commandOut = new AccountOutCommand(account,200);
// 创建一个调度者
Invoker invoker = new Invoker();
// 告诉调度者我要存钱
invoker.setCommand(commandOut);
// 干活
invoker.executeCommand();
}
});
// 查询余额
findViewById(R.id.account_balance).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 显示余额
mAccountDisplay.setText(account.getAccountAmout());
}
});
// 查询账单
findViewById(R.id.account_balance).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 显示账单
mAccountDisplay.setText(account.getBill());
}
});
}
}
这就实现了简单的命令模式下存取钱的流程,当然可以把查账单之类的也列入Commod类里面。
后记
设计模式的目的是为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 但是问题还得具体分析,如果设计模式离开了生产实际,那么就发挥不出它的长处了,所以具体情况适合用什么设计模式就可以使用,怎么说,设计模式就像是追妹子,你要在交往中明确对方喜欢什么套路,然后选择适合对方的套路放手去追,这样基本就能成了,设计模式也是的,在逻辑和需求的总结中,站在前人的键盘上,确定一套行之有效的设计模式,这件事就算成功了。