从智能家居扯到命令设计模式

概述:

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

应用场景:

日志记录,撤销操作,队列请求

优/缺点:

优点:

1、降低了系统耦合度。

2、新的命令可以很容易添加到系统中去

缺点:

使用命令模式可能会导致某些系统有过多的具体命令类。

前提引入:

最近大家都在搞智能家居,构建自己的生态,阿呆的老板身为中国五十万强公司的老板,岂能没有嗅到这其中的商机呢?于是让连忙阿呆停下手中的工作,毕竟作为公司唯一的技术人员,阿呆还是很受重用的。

老板;阿呆啊,你来公司已经有两年了吧,你摸着自己的良心给我说,我待你如何?

阿呆:那没得说,对我简直不能再好了,有好几次我都觉得好像我是您失散多年的父,不对,儿子一样。(冷汗...不会要开除我吧)

老板:你能这样说我就放心了,是这样,最近我看新闻说这个智能家居是一个新的潮流,常常跟你讲,我们要懂得抓住未来,你要是有我一半的智慧,也早就成为公司的二把手了。是这样的,我们公司三个员工,在管理上占据了我相当大的精力了,如果再来一家公司要我管理的话,那是真的两个脑袋也管不过来啊。所以我打算成立一个做智能家居的新公司,我看那个什么公司来着,小麦?就做的挺好的嘛。

阿呆:是小米。

老板:对对,小米,考虑到我们自身的情况确实和小米差点,所以新公司小木集团,我打算派你去管理。

阿呆:真的吗(感动中...虽然老板平时喜欢拖欠工资,把人当苦力,天天九九六,加班不给钱,.....但没想到老板组建分公司第一个想到的就是自己,放心吧老板,我阿呆追随你到天涯海角,你跑路我跟你跑!),那研发费用,还要招新员工的钱?

老板:等你盈利之前,就先从你工资里扣吧。

阿呆:吐血

好尬.....

阿呆看着自己那点工资,心想啥也做不出来啊,别说做家居了,买家居的钱都没有。那做什么呢,做电视吧,算了吧,做个遥控器还差不多? !!! 就做遥控器!

小木牌智能遥控器,一键配对,按键功能随心搭配,一个遥控器在手,去哪看电视都不愁!

那么问题来了,既然要做到遥控器每个按钮的功能可以更换,那势必不能按照传统的方法来开发了,有过之前的教训,阿呆已经明白,写一个类把所有功能写死是万万不能的,那应该怎么做呢,这时候就该我们的命令模式派上用场了,当然,这里直接举例代码说明是不太容易帮助我们刚学习设计模式的小伙伴们理解的,大家不妨这样想:

在一个军队中,将军突然渴了,于是想到张三是负责接水的,就让张三送水来喝,饿了,想起来厨师是李四,于是就让李四去做饭送来吃,当然,记住两个人的名字对于将军来说并非难事,那要是将军是个事儿多的人呢,可能就要记住成千上百个人的名字和他们对应的职务了,这对于将军来说肯定不能把精力花在记名字这件事情上,否则就会造成打仗打不好,这个时候我们引入管家这个概念,因为管家不需要打仗,所以管家有足够多的精力去记名字,名字过多时,我们也可以设立多个管家来解决,所有当将军饿的时候,只需要说一句"我饿了,送饭来"就行了,管家听到之后,于是把李四叫过来把饭做好,然后给将军享用。在这个例子中,将军是不知道李四是负责做饭的,李四也不知道将军的存在,所以即使换了别的人做将军,或者换了别的人做饭,只要管家还在,对于整个系统就是没有影响的,所以降低了将军和李四之间的耦合。因为有了管家这个角色的存在,我们甚至可以做到,李四把饭做好的时候,管家记录李四做的什么饭(应用场景中的日志记录),饭做的不好吃让李四回去重新做(撤销,更改等操作),同理,命令模式也是这样,调用者只负责发送命令,而不需要关心谁来具体执行业务逻辑。

看代码:

代码实战:

Receiver接口:接收者接口


/***
*
* @author 韩数
* 定义业务实现的行为。
*
*/
public interface Receiver {
//业务逻辑接口,接收者知道业务逻辑的具体实现方法
public void action();

}

UpReceiverImpl类:接收者遥控器打开功能实现


/***
*
* @author 韩数
* 业务逻辑的具体实现,在这里主要是指遥控器的开操作。
*
*/
public class UpReceiverImpl implements Receiver{

@Override
public void action() {
// TODO Auto-generated method stub
System.out.println("打开电视!");

}

}

Command:命令接口,定义命令的行为:

/***
*
* @author 韩数
* 命令接口,定义命令的行为,比如撤销,更改等操作都适合在这里定义。
*
*/
public interface Command {

/***
* 命令执行的方法
*/
public void execute();



}

ConcreteCommand:命令的具体实现类:

/****
*
* @author 韩数
* 具体的命令实现类,在这里完成Reciver和Command之间的绑定。
*
*/
public class ConcreteCommand implements Command {

private Receiver receiver;

public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}

//实际的业务逻辑是委托给Reciver对象来执行的。
@Override
public void execute() {
// TODO Auto-generated method stub
receiver.action();

}

}

Invoker:调用者

/***
*
* @author 韩数
* 调用者,调用者不知道是具体的服务提供方是谁,只知道对应的Command命令,通过命令中封装的具体服务实例,从而实现了代码间的解耦合。
*
*/
public class Invoker {

private Command command;

public void setCommand(Command command) {
this.command = command;
}

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


}

测试:

/***
*
* @author 客户端
* 模拟一个命令模式执行的流程
*
*/
public class Client {

public static void main(String[] args) {

Receiver receiver = new UpReceiverImpl();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.action();



}

}

OUTPUT:

打开电视!

总结:

以上就是命令模式的一个简单的实现了,至于如何实现操作的撤销,更改,记录等操作,我这里更多的是想小伙伴们自己去动脑实现,技术的养成并非一朝一夕,要经过自己的思考才能得到真正的理解,本系列笔记目前已经开源至github,如果需要本文的电子版markdown笔记和配套代码,可以前去下载。

暂无评论

文艺中二理工男,技术极客程序员

发表评论