不一样的命令模式(设计模式十五)
前言
什么是命令模式呢?其实是这样一个东西。
“行为请求者”与“行为实现者”通常呈现一种“紧耦合”
先介绍一下什么是行为请求者和行为实现者没有分开:
class Person()
{
public void eat()
{
//吃饭
}
public void sleep()
{
//碎觉
}
}
class ClientA()
{
public void do()
{
person.eat();
}
}
这个是行为请求者和行为实现者没有分开。
他们通过之间调用的方式,是一个紧耦合的关系。但是有些情况下,紧耦合并不适用。
现在又一个一个客户:
class ClientB()
{
public void do()
{
person.sleep();
}
}
比如说,现在clientA和clientB 非常多,并且是一个并发多线程的过程,但是又不立即执行,比如说订单系统,要保持高响应。
要达到这种目的就需要一个队列(当然也可以两个队列,但是如果person行为非常多,那么队列数量多的话难以维护),也就是说要把person.eat()和person.sleep()封装成一个具备公共接口或者公共父类对象。这就是命令模式的核心思想,把一个行为封装成一个对象。
把概念贴一下:
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
正文
那么可以这样写,下面为手写,不一定完全正确。
public abstract class Command
{
public abstract void excute();
}
public class EatCommand:Command
{
Peason peason;
public EatCommand(Peason peason)
{
this.Person=Person
}
public void excute()
{
peason.eat();
}
}
public class SleepCommand:Command
{
Peason peason;
public SleepCommand(Peason peason)
{
this.Person=Person
}
public void excute()
{
peason.sleep();
}
}
public class Manager
{
private static queue q=new queue();
public Manager()
{
}
public void add(Command command)
{
q.add(command);
}
public void excute()
{
if(q.Count!=0)
{
//不用担心这样写觉得command 会多余哈,编译器会帮我们优化,这样写更清晰
var command=q.Dequeue() as Command;
command.excute();
}
}
}
这里只写clientA:
class ClientA()
{
public void do()
{
//不要关心person怎么来的,可以new 一个或者工厂实例化,等等
EatCommand Eatcomment=new EatCommand(person);
//manager 单例,在另外一个线程中消费
manager.add(Eatcomment);
}
}
这样写就是将一个行为变成了一个对象,而行为请求者和行为执行者,耦合性降低,这样灵活性就上升了。
比如说,需要clientA 需要撤销功能。
public void do()
{
EatCommand Eatcomment=new EatCommand(person);
if(...)
{
manager.add(Eatcomment);
}
if(...)
{
manager.remove(Eatcomment);
}
manager.excute();
}
我这里没有实现remove,如果是这种的话,那么就不是一个队列而是一个集合或者别的。
这样可以自由控制行为,而且可以延迟执行,延迟执行的优点可以参考linq。
因为行为变成了对象,谁是执行者这个问题就弱化了(就是说当person传给了command,那么关注点和person就没有关系了),更多的关系到功能实现上了。
缺点:
使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。