命令模式

设计模式之命令模式

命令模式的介绍

命令模式从名字来看,就是老大发命令,小弟执行。但是深化解释,用模式来描述真实的世界命令情况。下面就用项目组为例子来讲述命令模式。

命令模式例子描述

在中国,项目经理就是一个项目的头,就是什么都要管,什么都要会的角色。我们假定一个项目组,这个项目的成员分工不同,分别为 需求组(Requirement Group rg),美工组(Page Grop pg),代码组(Code Group cg)。刚开始时候,客户作为甲方还是很乐意和每个组讨论,比如和需求组讨论需求,和美工组讨论页面,和代码组讨论实现,告诉他们修改这里,删除这里,增加这里等等。这是一种很常见的甲乙双方合作模式,甲方深入到乙方的项目开发中,我们把这个模式用类图表示一下:

在这里插入图片描述

这个类图很简单,客户和三个组都有交流,这也合情合理,如下是具体的实现,首先是抽象类,我们是面向借口或者抽象类编程的,哈哈哈:

package com.designpattern14;

public abstract class Group {
	
	//甲乙双方分开办公,你要和那个组讨论,你首先要找到这个组
	public abstract void find();
	
	//被要求增加功能
	public abstract void add();
	
	//被要求删除功能
	public abstract void delete();
	
	//被要求修改功能
	public abstract void change();
	
	//被要求给出所有的变更计划
	public abstract void plan();
}

大家看下这个抽象类的每个方法,是不是每个都是一个命令?增删改,计划!这就是命令模式中的命令接受者角色(Receiver),我们再看三个实现类,需求组最重要,没有需求还设计个啥,看下RequirementGroup的实现。

package com.designpattern14;

public class RequirementGroup extends Group{

	@Override
	public void find() {
		System.out.println("找到需求组。。。。。。。");
	}

	@Override
	public void add() {
		System.out.println("客户要求增加一项需求。。。。。。");
	}

	@Override
	public void delete() {
		System.out.println("客户要求删除一项需求。。。。。。");
	}

	@Override
	public void change() {
		System.out.println("客户要求修改一项需求。。。。。。。");
	}

	@Override
	public void plan() {
		System.out.println("客户要求需求变更计划。。。。。。。");
	}

}

然后看下项目的颜面,美工组PageGroup的实现:

package com.designpattern14;

public class PageGroup extends Group{

	@Override
	public void find() {
		System.out.println("找到美工组。。。。。。。");
	}

	@Override
	public void add() {
		System.out.println("客户要求增加一个页面。。。。。。");
	}

	@Override
	public void delete() {
		System.out.println("客户要求删除一个页面。。。。。。");
	}

	@Override
	public void change() {
		System.out.println("客户要求修改一个页面。。。。。。。");
	}

	@Override
	public void plan() {
		System.out.println("客户要求页面变更计划。。。。。。。");
	}

}

最后看下实现代码的代码组CodeGroup 的实现:

package com.designpattern14;

public class CodeGroup extends Group {

	@Override
	public void find() {
		System.out.println("找到代码组。。。。。。。");
	}

	@Override
	public void add() {
		System.out.println("客户要求增加一项功能。。。。。。");
	}

	@Override
	public void delete() {
		System.out.println("客户要求删除一项功能。。。。。。");
	}

	@Override
	public void change() {
		System.out.println("客户要求修改一项功能。。。。。。。");
	}

	@Override
	public void plan() {
		System.out.println("客户要求代码变更计划。。。。。。。");
	}

}

好啦,项目的主要三个支柱已经 完成了,看下客户怎么和我们谈。客户刚刚给了我们一份需求需要更改,要加点需求,看客户端Client的实现:

package com.designpattern14;

public class Client {
	public static void main(String[] args) {
		//首先找到需求组,过来谈需求,并修改
		System.out.println("---------客户要求增加一个需求----------");
		Group rg = new RequirementGroup();
		rg.find();
		rg.add();
		rg.plan();		
	}
}

看结果
在这里插入图片描述

好的,客户的需求达到了,增加需求是正常操作。然后过了段时间,客户说,界面多画了一个,来谈一谈,于是:

package com.designpattern14;

public class Client {
	public static void main(String[] args) {
		System.out.println("---------客户要求删除一个页面----------");
		Group pg = new PageGroup();
		pg.find();
		pg.delete();
		pg.plan();	
	}
}

运行结果如下:
在这里插入图片描述

然后某一天,客户又让代码组过去,说是代码实现有bug,然后又叫美工过去,布置一堆命令。但是问题来了,每次都是叫一个组过去,然后出计划,每次都这样,很烦。而且,很容易发生错误。比如,客户把美工叫过去,说要改页面,美工说需求组这么提的,客户又把需求组叫过去,一次次折腾,客户也烦了。于是,直接和项目经理说,“我不管里面内部怎么安排,给个接头人,我告诉他怎么做,增加页面了,添加功能需求了,里面内部自己协调,我只告诉他我要干什么就可以,我只关心最后的实现结果。”

项目经理一听,这样真好。于是有了如下的图:
在这里插入图片描述

类图中添加了不少,注意 Command 抽象类和Group抽象类没有关联关系,和Group的三个实现类有关。
Command 抽象类:客户发给我们的命令,引用三个工作组的成员变量,供子类使用;定义一个抽象execute,由子类实现。
Group 抽象类 实际是Receiver(接受者),实际任务的完成者,具体实现由子类实现。
Invoker 实现类 :项目的接头人,项目经理。setCommand 接受客户发给我们的命令,action方法是执行客户的命令。

下面看下Command的代码:

package com.designpattern14;

public abstract class Command {
	
	//把3个组都定义好,子类可以直接使用
	protected RequirementGroup rg = new RequirementGroup();
	protected PageGroup pg = new PageGroup();
	protected CodeGroup cg = new CodeGroup();
	
	//只要一个方法,你要我做什么事
	public abstract void execute();

}

看下简单的两个命令实现类:
增加需求的命令实现:

package com.designpattern14;

public class AddRequeirementCommand extends Command {

	@Override
	public void execute() {
		super.rg.find();
		super.rg.add();
		super.rg.plan();
		super.flag = true;
	}

}

删除页面的命令实现

package com.designpattern14;

public class DeletePageCommand extends Command{

	@Override
	public void execute() {
		super.pg.find();
		super.pg.delete();
		super.pg.plan();
		super.flag = true;
	}

}

Command 抽象类还可以有很多子类,比如增加一些功能命令,删除一份需求命令等等,都很简单。

下面看下接头人,也就是项目经理,Invoker的具体实现:

package com.designpattern14;

/*
 * 接头人的职责就是接受命令,并执行
 */
public class Invoker {
	private Command command;
	
	//客户发出命令
	public void setCommand(Command command) {
		this.command = command;
	}
	
	//执行客户命令
	public void  action() {
		this.command.execute();
	}
}

然后我们看下客户提出变更的过程:

package com.designpattern14;

public class Client {
	public static void main(String[] args) {
		Invoker invoker = new Invoker();
		
		//客户要求增加一项需求
		Command command = new AddRequeirementCommand();
		//接头人接收到命令
		invoker.setCommand(command);
		//接头人执行命令
		invoker.action();
	
	}
}

看下结果:
在这里插入图片描述

而客户要删除一个页面,需要如下代码:

package com.designpattern14;

public class Client {
	public static void main(String[] args) {
		Invoker invoker = new Invoker();
		
		//客户要求增加一项需求
		Command command = new DeletePageCommand();
		//接头人接收到命令
		invoker.setCommand(command);
		//接头人执行命令
		invoker.action();		
	}
}

看下前后的Client的代码对比,只是改了一行代码,就完成了一个命令,而且客户也不用知道谁来做这个操作,高内聚就体现出来了,这就是命令模式,具体的通用类图如下:
在这里插入图片描述
这个类图里,我们看到三个角色:

Receiver 角色:这个是干活的,命令传递到这里是应该执行的,具体到我们的例子中就是Group的三个子类。
Command 角色: 就是命令,需要我执行的所有命令都在这里声明。
Invoker 角色: 调用者,接受到命令,并执行命令,例子中的项目经理角色。

命令模式在项目中使用比较频繁,因为它把请求方和执行方分开了,扩展性也有很好的保障。但是,命令模式也有缺点,Command的子类可能有很多,膨胀的非常多,这个项目中怎么使用就是看大家了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值