五分钟一个设计模式,用最简单的方法来描述设计模式。
小米智能模块的例子
前一段小米的老总雷军在印度的全英文演讲想必大家都还历历在目,不过今天我们讨论的主题不是那次演讲,而是小米智能模块。小米4发布时,雷军说,小米已经开发了一个智能模块,只要电器厂商将这个智能模块集成到自家的电器中,就可以用小米手机来控制它,并且小米智能模块才22块钱。是不是一件很牛X的事情?这个事情,从宏观上来看,通过小米手机来控制所有集成了智能模块的电器,就是使用了命令模式!下面我们来模拟一下这个事情。
首先,有一些家用电器的厂商,他们能控制自家的电器的开关。
/// <summary>
/// 大灯
/// </summary>
public class Light
{
public void LightOn()
{
Console.WriteLine("灯亮了");
}
public void LightOff()
{
Console.WriteLine("灯灭了");
}
}
/// <summary>
/// 热水器
/// </summary>
public class Heater
{
public void HeaterOn()
{
Console.WriteLine("加热中");
}
public void HeaterOff()
{
Console.WriteLine("停止加热");
}
}
/// <summary>
/// 冰箱厂商提供的api
/// </summary>
public class Fridge
{
public void FridgeOn()
{
Console.WriteLine("冰箱开了");
}
public void FridgeOff()
{
Console.WriteLine("冰箱关了");
}
}
}
这么多个厂商,小米手机怎么能控制他们呢?让他们实现相同的类吗?这就要求所有厂商修改自家的类,他们肯定不愿意。这就会用到一个新的概念,组合。小米手机提供一个统一的智能模块,这个智能模块和各厂商的类组合到一块,然后小米手机直接控制智能模块就OK了。智能模块到底是什么呢,它包含了很多个定义好的类每一个类控制一种家用电器,如,大灯控制器,热水器控制器,冰箱控制器,电视控制器,小米盒子控制器,等等各种控制器。每一种具体的控制器都能在小米手机的控制器应用中找到一个对应的按钮。
下面来看看这个智能模块到底是什么。它是一组类,实现了同一个接口 ICommand
public interface ICommand
{
void Execute();
}
下面是智能控制模块中庞大的一组类,我们来列举几个
大灯控制器
public class LightOnCommand : ICommand
{
Light light;
public LightOnCommand(Light light)
{
this.light = light;
}
public void Execute()
{
light.LightOn();
}
}
class LightOffCommand : ICommand
{
Light light;
public LightOffCommand(Light light)
{
this.light = light;
}
public void Execute()
{
this.light.LightOff();
}
}
加热器控制器
public class HeaterOnCommand : ICommand
{
Heater heater;
public HeaterOnCommand(Heater heater)
{
this.heater = heater;
}
public void Execute()
{
this.heater.HeaterOn();
}
}
public class HeaterOffCommand : ICommand
{
Heater heater;
public HeaterOffCommand(Heater heater)
{
this.heater = heater;
}
public void Execute()
{
this.heater.HeaterOff();
}
}
类太多了,不列举了。所有的类都有这样的特点:
- 实现了ICommand接口
- 一个请求(或命令)就是一个类
- 不直接执行命令,而是由跟它组合的具体电器对象来执行命令
有了这个智能模块,小米手机的调用就简单了
class Program
{
static void Main(string[] args)
{
//厂商开发电器
Light light = new Light();
Heater heater = new Heater();
//厂商将自家电器集成小米智能模块
LightOnCommand lightOnCommand = new LightOnCommand(light);
LightOffCommand lightOffCommand = new LightOffCommand(light);
HeaterOnCommand heaterOnCommand = new HeaterOnCommand(heater);
HeaterOffCommand heaterOffCommand = new HeaterOffCommand(heater);
//小米手机很方便地调用
lightOnCommand.Execute();
lightOffCommand.Execute();
heaterOnCommand.Execute();
heaterOffCommand.Execute();
}
}
程序的运行结果是:
灯亮了
灯灭了
加热中
停止加热
认识命令模式
看到了命令模式的强大,下面我们来认识一下命令模式
命令模式的定义是:将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化,对请求排队或记录日志,以及支持可撤销操作。
命令模式的关键之处把每一个具体的请求都封装成了一个对象,即命令对象,这些请求实现了同一个接口,而且还不亲自执行具体任务。每一个命令对象都和命令的具体执行者组合在一起,由命令的具体执行者来执行命令。
在上面的例子中,小米智能模块中的每一个类,都是命令对象,他们实现了同一个接口,跟具体电器组合,在Execute方法中调用电器的方法来执行任务。小米手机通过ICommand接口控制智能模块,智能模块调用具体的电器来完成开或关。
关于撤销,也不难实现。在我们的ICommand接口中,只定义了一个Execute方法,我们只需要加入一个Undo方法,让所有的命令对象去实现就好了。这样子的话,在客户端得到的命令对象就可以直接调用Undo方法了。
用命令模式来分析完小米智能盒子后,我想问你:Are you OK ?