命令模式--java

1.概念

  将来自客户端的请求传入一个对象,从而使你可用不同的请求对客户进行参数化。用于“行为请求者”与“行为实现者”解耦,可实现二者之间的松耦合,以便适应变化。分离变化与不变的因素。

   在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。

但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。

Command模式可应用于
a)整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
b)调用前后需要对调用参数进行某些处理。
c)调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。

Command模式有如下效果:
a)将调用操作的对象和知道如何实现该操作的对象解耦。
b)Command是头等对象。他们可以像其他对象一样被操作和扩展。
c)你可将多个命令装配成一个符合命令。
d)增加新的Command很容易,因为这无需改变现有的类。

2  模式结构和说明

        命令模式的结构如图2所示:


                                                  图2  命令模式结构图
Command:
        定义命令的接口,声明执行的方法。
ConcreteCommand:
        命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
Receiver:
        接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
Invoker:
        要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
Client:
        创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。


3举例说明:

张三晚上到烧烤店吃夜宵,进店子坐下后,服务员过来接待,张三对服务员说来份烤羊肉和烤鸡翅,随后服务员去通知烧烤师傅,让其烧烤。

UML


package wei.com;

//烧烤师傅--Receiver
public class Barbecuer
{
	public void kaoyangrou()  //烤羊肉动作
	{
		System.out.println("烤羊肉");
	}
	
	public void kaojichi()   //烤鸡翅动作
	{
		System.out.println("烤鸡翅");
	}

}

package wei.com;

abstract public class Command
{
	protected Barbecuer reciver;
	
    public Command(Barbecuer barbecuer)
	{
    	this.reciver = barbecuer;
	}
    
    //执行命令
   abstract public void ExcuteCommand();
   
   public String toString()
   {
	   return "命令模式.";
   }
}

package wei.com;

public class KaoyangrouCommand extends Command
{

	public KaoyangrouCommand(Barbecuer barbecuer)
	{
		super(barbecuer);
	}

	@Override
	public void ExcuteCommand()
	{
		this.reciver.kaoyangrou();
	}
	
	   public String toString()
	   {
		   return super.toString()+"烤羊肉";
	   }
	
}


package wei.com;

public class KaojichiCommand extends Command
{
	public KaojichiCommand(Barbecuer barbecuer)
	{
		super(barbecuer);
	}

	@Override
	public void ExcuteCommand()
	{
		this.reciver.kaojichi();
	}
	
	   public String toString()
	   {
		   return super.toString()+"烤鸡翅";
	   }

}

package wei.com;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

//---Invoker
public class Waiter
{
	private ArrayList<Command> orders = new ArrayList<Command>();
	
	//添加命令
	public void addCommand(Command command)
	{
		if(command.toString().equals("命令模式.烤羊肉") )
		{
			System.out.println("对不起,烤羊肉卖完了,请点其他菜");
		}
		else
		{
			orders.add(command);
			
			String msg="";  
		    Date date = new Date();  
		    SimpleDateFormat sdf = new SimpleDateFormat("YYYY/MM/dd HH:mm:ss.SSS");  
		    msg+= sdf.format(date); 
		        

			System.out.println("增加订单:" +command.toString()+"    Time: "+msg);
		}
	}
	
	//删除命令
	public void removeCommand(Command command)
	{
		orders.remove(command);
		
		String msg="";  
	    Date date = new Date();  
	    SimpleDateFormat sdf = new SimpleDateFormat("YYYY/MM/dd HH:mm:ss.SSS");  
	    msg+= sdf.format(date); 
	        
		
		System.out.println("取消订单:" +command.toString()+"    Time: "+msg);
	}
	

	//通知
	public void Notify()
	{
		for (Command eCommand : orders)
		{
			eCommand.ExcuteCommand();
		}
	}
	

}
package wei.com;


public class Client
{
	public static void main(String[] args) throws InterruptedException
	{
		//开店前奏
		Barbecuer barbecuer = new Barbecuer();             //厨师准备好
		Command button1 = new KaojichiCommand(barbecuer);  //按键1--点烤鸡翅
		Command button2 = new KaoyangrouCommand(barbecuer);//按键2--点烤羊肉
		Waiter waiter = new Waiter();                      //服务员准备好
		
		//顾客 开始点菜--服务员服务
		waiter.addCommand(button1);  //点烤鸡翅
		Thread.sleep(1000*1);
		
		waiter.addCommand(button2);  //点烤羊肉
		Thread.sleep(1000*1);

		waiter.removeCommand(button1);//取消烤鸡翅
		
		waiter.Notify();

	}

}


结果:


4.应用场景

在下面的情况下应当考虑使用命令模式:

1)使用命令模式作为"CallBack"在面向对象系统中的替代。"CallBack"讲的便是先将一个函数登记上,然后在以后调用此函数。

2)需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。命令对象可以在串形化之后传送到另外一台机器上去。

3)系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果。

4)如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用Execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值