生活中的设计模式之命令(Command)模式

命令模式在日常生活中非常普遍。只要涉及到控制行为,就会有命令模式的出现。

今天的分析,以日常生活中开关灯为例,从耦合较高的代码一步步进行改进。

Part1:

问题1:编写代码,实现生活中开关灯的操作

分析:和现实生活一样,要实现开关灯,那么必须要有两个物体(对象),灯和开关。

灯有两个状态,开(on),关(off)。

开关有两个动作,开灯(turnonLight),关灯(turnoffLight)。简单实现代码如下:

灯类:

class Light{
	//灯打开状态
	public void on(){
		System.out.println("light is on");
	}
	//灯关闭状态
	public void off(){
		System.out.println("light is off");
	}
}

开关类:

class Switch{
	private Light l1 = null;
	public Switch(Light l){
		l1=l;
	}
	//使用开关开灯
	public void turnonLight(){
		System.out.print("press the switch and  ");
		l1.on();
	}
	//使用开关关灯
	public void turnoffLight(){
		System.out.print("press the switch and  ");
		l1.off();
	}
}

场景类:

public class LightControl {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Light light = new Light();			//买一个灯回家
		Switch lightSwitch = new Switch(light);//安装灯对应的开关
		lightSwitch.turnonLight();//使用开关开灯
		lightSwitch.turnoffLight();//使用开关关灯
	}
}

输出为:

press the switch and  light is on
press the switch and  light is off

Part2:

上面代码实现了简单的开关控制,但是我们发现switch类封装的操作太多,不利于扩展,比如遇到了下面的问题。

问题2:购买了一种灯,这种灯的开关可以设置灯的颜色,晚上回家,我先将灯的颜色设置为黄色,然后打开,睡觉时关闭。

分析:开关增加了一个新的命令,需要修改开关类,再增加setColor()方法。

如果这种需求很多,每次都要修改原有类,不仅不利于代码维护,还增加了大量的测试时间。

Note:好的代码结构应该是【对扩展开放,对修改关闭】。【】内为引用内容。

那么,就需要将switch类进行分解,使得每一个命令单独成类。由于每一个命令实现方式类似,为了后续扩展,抽象出命令抽象类。

为什么不用接口呢?因为每个命令类中都要维护一个Light变量,而接口中所有的变量都是static final的常量。

abstract class Command{
	protected Light l;   //灯对象
	public Command(Light l1){
		l = l1;
	}
	public abstract void action();  //命令执行
}

每个命令封装成类:

开灯类:

class TurnOn extends Command{
	public TurnOn(Light l1){
		super(l1);
	}
	public void action(){
		l.on();				//开灯
	}
}

关灯及设置颜色与开灯类结构相同,不再赘述。

因为新灯增加了功能,构建的新类如下:

class Light{
	private String color;
	//灯打开状态
	public void on(){
		System.out.println("light is on");
	}
	//灯关闭状态
	public void off(){
		System.out.println( "light is off");
	}
	//******(新添加)设置颜色为黄色
	public void color(){
		System.out.print("Yellow ");
	}
}

场景类:

public class LightControl {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Light light = new Light();			//买一个灯回家
		SetColor sc = new SetColor(light);		//设置灯的颜色
		sc.action();
		TurnOn turnon = new TurnOn(light);		//开灯
		turnon.action();
		TurnOff turnoff = new TurnOff(light);		//关灯
		turnoff.action();
		
	}
}

输出:

Yellow light is on
light is off

通过将switch分解,现在每次需要增加新的命令,只需要创建对应的新类,然后调用即可,无需修改原来存在的类。

Part3:

上面的代码耦合性已经不高,但是还是有点问题。

问题3:如果某些命令需要组合使用,比如在开灯前,要check一下周围的光线,或者需要执行其它的命令,那我每次都需要new一个新的对象,然后执行命令对应的run方法。

有没有更简单的方式呢?

解决方案:将所有命令封装到一个类中,通过组合不同的命令,实现控制。(Invoker类很像观察者模式中被观察对象类)

分析:创建Control类,Control类要有运行(execute)方法及绑定命令(setCommand)的方法。

Control类代码:

class Control{
	List<Command> listCmd = new LinkedList<Command>();
	
	//绑定Command
	public void setCommand(List<Command> c){
		listCmd = c;
	}
	//调用Command运行
	public void execute(){
		Iterator<Command> it = listCmd.iterator();
		while(it.hasNext()){
			it.next().action();
		}
	}
}


场景类代码:

public class LightControl {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Light light = new Light();			//买一个灯回家
		SetColor sc = new SetColor(light);	//灯的颜色设置开关
		TurnOn turnon = new TurnOn(light);	//灯的打开开关
		TurnOff turnoff = new TurnOff(light);//灯的关闭开关
		List<Command> l1 = new LinkedList<Command>();
		l1.add(sc);
		l1.add(turnon);
		l1.add(turnoff);
		Control ctr = new Control();
		ctr.setCommand(l1);
		ctr.execute();    					//命令单个或者组合使用
	}
}



  
  
输出:

Yellow light is onlight is off



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值