命令模式
简介:它将请求发送者,请求接收者解耦,可以让相同的发送者对应不同的接收者。
命令模式定义:将一个请求封装成一个对象,从而通过不同的请求将客户端参数化,实现了请求排队,记录请求日志,可撤销操作
案例:烧烤摊和烧烤店
源代码:V1.0
package org.zangyu.Command;
public class Command {
public static void main(String[] args) {
// TODO Auto-generated method stub
Barbecuer boy =new Barbecuer();
boy.BakeMutton();
boy.BakeChickWing();
}
}
class Barbecuer{
//烤羊肉
public void BakeMutton()
{
System.out.println("烤羊肉串!");
}
//烤鸡翅
public void BakeChickWing()
{
System.out.println("烤鸡翅!");
}
}
问题:店主直接与消费者对话,耦合性太高,店主需要实现的功能过度
解决:引进服务者类,成为店长和消费者之间沟通的桥梁
源代码:V2.0
package org.zangyu.Command;
public class Command1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Barbecuer boy = new Barbecuer();
Commands command1=new BakeMuttonCommand(boy);
Commands command2=new BakeChickenWingCommand(boy);
Commands command3=new BakeChickenWingCommand(boy);
Waiter girl=new Waiter();
//开业
girl.SetOrder(command1);
girl.Notify();
girl.SetOrder(command2);
girl.Notify();
girl.SetOrder(command3);
girl.Notify();
}
}
class Barbecuer{
public void BakeMutton()
{
System.out.println("烤羊肉串!");
}
//烤鸡翅
public void BakeChickWing()
{
System.out.println("烤鸡翅!");
}
}
abstract class Commands {// 声明执行的接口
protected Barbecuer receiver;
public Commands(Barbecuer receiver) {
super();
this.receiver = receiver;
}
//执行命令
public abstract void ExcuteCommand();
}
//烤羊肉串命令
class BakeMuttonCommand extends Commands{
public BakeMuttonCommand(Barbecuer receiver) {
super(receiver);
// TODO Auto-generated constructor stub
}
@Override
public void ExcuteCommand() {
// TODO Auto-generated method stub
this.receiver.BakeMutton();
}
}
class BakeChickenWingCommand extends Commands{
public BakeChickenWingCommand(Barbecuer receiver) {
super(receiver);
// TODO Auto-generated constructor stub
}
@Override
public void ExcuteCommand() {
// TODO Auto-generated method stub
this.receiver.BakeChickWing();
}
}
class Waiter{//服务员类
//增加存放具体命令的容器
private Commands command;
//设置订单
public void SetOrder(Commands command)
{
this.command=command;
}
//通知执行
public void Notify()
{
command.ExcuteCommand();
}
}
服务员只能记住一个命令,不符合实际情况
改进:使用链表
源代码:V3.0
package org.zangyu.Command;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
public class Command2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Barbecuer boy = new Barbecuer();
Commands command1=new BakeMuttonCommand(boy);
Commands command2=new BakeChickenWingCommand(boy);
Commands command3=new BakeChickenWingCommand(boy);
Waiter girl=new Waiter();
//开业点餐
girl.SetOrder(command1);
girl.SetOrder(command2);
girl.SetOrder(command3);
//通知厨房
girl.Notify();
}
}
class Barbecuer{
public void BakeMutton()
{
System.out.println("烤羊肉串!");
}
//烤鸡翅
public void BakeChickWing()
{
System.out.println("烤鸡翅!");
}
}
abstract class Commands {// 声明执行的接口
protected Barbecuer receiver;
public Commands(Barbecuer receiver) {
super();
this.receiver = receiver;
}
//执行命令
public abstract void ExcuteCommand();
}
//烤羊肉串命令
class BakeMuttonCommand extends Commands{
public BakeMuttonCommand(Barbecuer receiver) {
super(receiver);
// TODO Auto-generated constructor stub
}
@Override
public void ExcuteCommand() {
// TODO Auto-generated method stub
this.receiver.BakeMutton();
}
}
class BakeChickenWingCommand extends Commands{
public BakeChickenWingCommand(Barbecuer receiver) {
super(receiver);
// TODO Auto-generated constructor stub
}
@Override
public void ExcuteCommand() {
// TODO Auto-generated method stub
this.receiver.BakeChickWing();
}
}
class Waiter{//服务员类
//增加存放具体命令的容器
private List commands =new ArrayList<Commands>();
//设置订单
public void SetOrder(Commands command)
{
if(command.getClass().getName().equals("org.zangyu.Command.BakeChickenWingCommand"))
{
System.out.println("服务员:鸡翅没了");
}else
{
commands.add(command);
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//设置日期格式
//记录日志,以备结账,new date()获取当前系统时间
System.out.println("增加订单:"+command.getClass().getName()+"时间:"+df.format(new Date()));
}
}
//取消订单
public void CancelOrder(Commands command)
{
commands.remove(command);
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//设置日期格式
//记录日志,以备结账,new date()获取当前系统时间
System.out.println("取消订单:"+command.getClass().getName()+"时间:"+df.format(new Date()));
}
//通知执行
public void Notify()
{
Iterator <Commands> cmd = commands.iterator();
while(cmd.hasNext()) {
cmd.next().ExcuteCommand();
}
}
}
命令模式基本框架——源代码
package org.zangyu.Command;
public class Command3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Receiver r =new Receiver();
Commands c=new ConcreteCommand(r);
Invoker i =new Invoker();
i.setCommands(c);
i.ExecuteCommand();
}
}
class Receiver
{
public void Action()
{
System.out.println("执行命令");
}
}
//用来声明执行的命令的接口
abstract class Commands
{
protected Receiver receiver;
public Commands(Receiver receiver) {
super();
this.receiver = receiver;
}
abstract public void Execte();
}
//具体命令类
class ConcreteCommand extends Commands
{
public ConcreteCommand(Receiver receiver) {
super(receiver);
// TODO Auto-generated constructor stub
}
@Override
public void Execte() {
// TODO Auto-generated method stub
receiver.Action();
}
}
//要求该命令执行这个请求
class Invoker
{
private Commands commands;
public Commands getCommands() {
return commands;
}
public void setCommands(Commands commands) {
this.commands = commands;
}
public void ExecuteCommand()
{
commands.Execte();
}
}
优点:
类间解耦:调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用Command 抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。
可扩展性:Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严 重的代码耦合。
命令模式结合其他模式会更优秀:命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少 Command子类的膨胀问题。
缺点:
命令模式也是有缺点的,请看Command的子类:如果有N个命令,问题就出来 了,Command的子类就可不是几个,而是N个,这个类膨胀得非常大,这个就需要读者在项 目中慎重考虑使用。
使用时机:
当需要先将一个函数登记上,然后再以后调用此函数时,就需要使用命令模式,其实这就是回调函数。
有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系