Java设计模式:命令模式

1.命令模式

命令模式(Command)属于对象的行为模式。

命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。


2.命令模式的类图


参与的角色:

  • Client:客户角色,创建了一个具体命令(ConcreteCommand)对象并确定其接收者。
  • Command:命令角色:抽象命令接口,定义了命令的行为。
  • ConcreteCommand:具体命令。定义一个接受者和行为之间的弱耦合;实现执行方法execute,负责调用接收者的相应操作。
  • Invoker:请求者角色。负责调用命令对象执行请求,相关方法叫做行动方法action。
  • Receiver:接收者角色。负责具体实施和执行一个请求。

3.示例代码

Client(客户端)
public class Client
{
    public static void main(String[] args)
    {
    	/**
    	 * 命令使用顺序,创建接收者,如果没有接收者(可以没有接收者),创建命令,请求者,然后调用请求者执行行动.
    	 */
        Receiver receiver = new Receiver();
        Command command = new ConcreteCommand(receiver);
    	Invoker invoker = new Invoker( command );

        invoker.action();
    }
 
}

Command(抽象命令)
public interface Command {
    void execute();
}
ConcreteCommand(具体命令)
public class ConcreteCommand implements Command
{
    public ConcreteCommand(Receiver receiver)
    {
        this.receiver = receiver;
    }

    /**
     * 执行方法
     */
    public void execute()
    {
        receiver.action();
    }

    private Receiver receiver;
}
Invoker(请求者)
public class Invoker
{
	/**
	 * 构造
	 * @param command
	 */
    public Invoker(Command command)
    {
        this.command = command;
    }

    public void action()
    {
		command.execute();
    }

   
    private Command command;
}
Receiver(接收者),命令的具体执行者
public class Receiver
{
    public Receiver()
    {
        
    }

    /**
     * 行动方法
     */
    public void action()
    {
        System.out.println("Action has been taken.");
    }
}

4.一个例子:操作录音机


系统需求

有一种录音机,录音机有播音(play)、倒带(rewind)和停止(功能)。用Java语言模拟这个系统。
录音机的键盘是请求者(invoker)角色;使用者是客户;而录音机是接收者角色。提炼一个抽象类Command扮演抽命令,此系统有PlayCommand,StopCommand和RewindCommand3个具体命令。

系统类图

如下:




代码实现

Keypad(请求者)
/**
 * 	接收者角色
 */
public class Keypad
{
   
	private Command playCmd;

    
    private Command rewindCmd;

    private Command stopCmd;
	
    /**
     * 构造函数,参数是命令
     * @param play
     * @param stop
     * @param rewind
     */
	public Keypad(Command play, Command stop, Command rewind)
	{
        // concrete Command registers itself with the invoker
		playCmd = play;
		stopCmd = stop;
        rewindCmd = rewind;
	}
	
	//执行方法
	public void play()
	{
		playCmd.execute();
	}
	public void stop()
	{
		stopCmd.execute();
	}
    public void rewind()
    {
        rewindCmd.execute();
    }
}

Command(抽象命令)
/**
 *  抽象命令
 */

public interface Command
{
	public abstract void execute ( );
}
PlayCommand(具体命令)

public class PlayCommand implements Command
{
	private AudioPlayer myAudio;

	public PlayCommand ( AudioPlayer a)
    {
		myAudio = a;
	}

	public void execute( )
    {
		myAudio.play();
	}
}
StopCommand(具体命令)
public class StopCommand implements Command
{
   
    private AudioPlayer myAudio;
	
    
	public StopCommand ( AudioPlayer a)
    {
		myAudio = a;
	}
	public void execute( )
    {
		myAudio.stop();
	}
}

RewindCommand(具体命令)

public class RewindCommand implements Command
{
	private AudioPlayer myAudio;

	public RewindCommand ( AudioPlayer a)
    {
	    myAudio = a;
	}
	public void execute()
    {
	    myAudio.rewind();
	}
}

AudioPlayer(接收者)
public class AudioPlayer
{
	public void play( )
	{
		System.out.println("Playing...");
	}

	public void rewind( )
	{
		System.out.println("Rewinding...");
	}
	
	public void stop()
	{
		System.out.println("Stopped.");
	}                                                                    
}

Client(客户端)
/**
 * 	客户端
 */
public class Client
{
    /**
     *键盘,持有Invoker角色
     */
    private static Keypad keypad ;

    /**
     *接受者角色 
     */
    private static AudioPlayer myAudio = new AudioPlayer();

	public static void main(String[] args)
	{
    	test1();
	}

    private static void test1()
    {
    	Command play = new PlayCommand(myAudio);
        Command stop = new StopCommand(myAudio);
        Command rewind = new RewindCommand(myAudio);

        keypad = new Keypad(play, stop, rewind);

        keypad.play();
        keypad.stop();
        keypad.rewind();

        keypad.stop();
        keypad.play();
        keypad.stop();
    }
}  

运行效果:
Playing...
Stopped.
Rewinding...
Stopped.
Playing...
Stopped.

添加宏命令

设想:添加一个宏命令键,把设置好的命令按顺序执行。只需要增加一个宏命令,而不用修改接收者。增加宏命令,使用组合模式。


MacroCommand(宏命令的接口)继承与Command,增加了操作子命令的接口。

public interface MacroCommand extends Command
{
	void execute();
	
	void remove(Command toRemove);
	
	void add(Command toAdd);
}

MacroAudioCommand(宏命令实现)
public class MacroAudioCommand implements MacroCommand
{
     private List<Command> commandList = new ArrayList<Command>();

     public void add(Command toAdd)
     {          
		commandList.add(toAdd);
     }

     public void remove(int index)
     {
		commandList.remove(index);
     }

     public void remove(Command toRemove)
     {
		commandList.remove(toRemove);
		
     }

     public void execute() 
     { 
		Command nextCommand;

		/**
		 * 子命令顺序执行
		 */
		for (int i=0; i < commandList.size(); i++)
		{
			nextCommand = commandList.get(i);
			nextCommand.execute();
        }
     } 
}

Client(客户端)
public class Client {
	/**
	 * 键盘,持有Invoker角色
	 */
	private static Keypad keypad;

	/**
	 * 接受者角色
	 */
	private static AudioPlayer myAudio = new AudioPlayer();

	public static void main(String[] args) {
		testMacroCommand();
	}

	private static void test1() {
		Command play = new PlayCommand(myAudio);
		Command stop = new StopCommand(myAudio);
		Command rewind = new RewindCommand(myAudio);

		keypad = new Keypad(play, stop, rewind);

		keypad.play();
		keypad.stop();
		keypad.rewind();

		keypad.stop();
		keypad.play();
		keypad.stop();
	}

	private static void testMacroCommand() {
		
		Command play = new PlayCommand(myAudio);
		Command stop = new StopCommand(myAudio);
		Command rewind = new RewindCommand(myAudio);
		
		MacroCommand macro = new MacroAudioCommand();
		macro.add(play);
		macro.add(stop);
		macro.add(rewind);
		
		macro.add(play);
		macro.add(stop);
		macro.add(rewind);
		
		macro.execute();
		
		
	}
}

运行效果和test1一致。

5.让命令模式支持undo和redo

要让命令模式支持撤销和恢复功能,首先,抽象命令需要增加接口undo
public interface Command
{
	public abstract void execute ( );
	
	public abstract void undo ( );
	
	
	
}

然后,具体命令类需要存储状态信息,包括:
(1)接收者对象实际上实施请求所代表的的操作;
(2)对接收者对象所作出的操作所需要的参数;
(3)接收者类的最初的状态。接收者必须提供方法,使命令类可以控制接收者恢复原有状态。

最后,系统需要存储被执行过命令,当undo时,逆序遍历命令,执行undo,当redo时,顺序遍历命令,执行execute。

6.在什么情况下使用命令模式

  • 使用命令模式作为callback在面向对象系统中的替代。callback讲的是:在面向过程编程中先将一个函数登记上,然后在以后调用此函数。
  • 需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求者可以有不同的生命周期。
  • 系统需要支持命令的撤销。
  • 系统需要支持命令的redo,一个系统将所有的数据更新写到日志里,当系统崩溃时,可以读取日志,添加命令,然后redo,恢复数据。

7.命令模式的优点和缺点

优点:
  1. 命令模式把请求一个操作的对象(客户端)与知道怎么执行一个操作的对象(接收者)分开。
  2. 命令类容易修改和扩展。
  3. 容易实现合成命令
缺点:具体命令类可能有很多。






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值