
·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> 设计模式(10)---命令模式
一、引言:
路边有一个烤肉摊,有一位老板负责给客人烧烤食物。如果客人很少,老板都能准确记住大家的要求,随着客人的增多,要求越来越多,老板很难满足大家要求,老板应该怎么办?
首先说明为什么客人多了,老板满足不了大家的要求,因为“用程序猿的话说是因为:紧耦合”。松耦合就能很好的解决此问题,也就是本文介绍的命令模式。先给出紧耦合代码:
class PRogram
{
static void Main(string[] args)
{
Receiver receiver = new Receiver();
receiver.BakeChickenWing();
Console.Read();
}
}
public class Receiver//boss
{
public void BakeMutton()
{
Console.WriteLine("bake mutton");
}
public void BakeChickenWing()
{
Console.WriteLine("bake chickenwing");
}
}
View Code
二、定义:
命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销操作。
解释:将请求命令封装为一个对象,并用日志记录下来,其中它支持命令撤销功能。
三、UML图及基本代码:

基本代码:
class Receicer
{
public void Action()
{
Console.WriteLine("执行请求");
}
}
abstract class Command
{
protected Receicer receiver;
public Command(Receicer receiver)
{
this.receiver = receiver;
}
abstract public void Execute();
}
class ConcreteCommand : Command
{
public ConcreteCommand(Receicer receiver)
: base(receiver)
{ }
public override void Execute()
{
receiver.Action();
}
}
class Invoker
{
private Command command;
public void SetCommand(Command command)
{
this.command = command;
}
public void ExecuteCommand()
{
command.Execute();
}
}
调用:
Receicer receiver = new Receicer();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.SetCommand(command);
invoker.ExecuteCommand();
解释:映射客人到酒店就餐。Receiver是命令的接收者,相当于酒店中的大厨;Command命令抽象类,ConcreteCommand是具体的命令,相当于点菜请求,命令中应该包含命令的接收者。Invoke是命令的传达者,相当于酒店的服务员,负责记录客人点菜请求,并传达给后厨。
四、举例说明:
学校高一学生进行军训,校长发布让学生跑10000米的命令。整个过程:校长发布命令给军训教官,教官传达校长命令给学生,学生接收到命令后执行相应的操作。在下面实例中,Receiver是学生,操作跑10000米的命令。Command是命令,必需知道命令的接收者。Drillmaster是教官,教官必需知道命令是什么,并传达命令。
//校长发布学生跑1000米的命令,教官传达此命令给学生,学生是命令的接收者
//客户端:校长,命令的发出者必须知道具体的命令、接受者、传达命令者
class Program
{
static void Main(string[] args)
{
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Drillmaster drillmaster = new Drillmaster(command);
drillmaster.ExecuteCommand();
Console.Read();
}
}
//命令接收者
public class Receiver
{
public void Run1000Meters()
{
Console.WriteLine("跑10000米");
}
}
//抽象命令
public abstract class Command
{
protected Receiver receiver;
public Command(Receiver receiver)
{
this.receiver = receiver;
}
public abstract void Action();
}
//具体的命令,必须知道命令接受者
public class ConcreteCommand : Command
{
public ConcreteCommand(Receiver receiver)
: base(receiver)
{ }
public override void Action()
{
receiver.Run1000Meters();
}
}
//教官:命令的传达者,负责调用命令对象的方法来保证命令执行
public class Drillmaster
{
public Command command;
public Drillmaster(Command command)
{
this.command = command;
}
public void ExecuteCommand()
{
command.Action();
}
}
View Code
五、解决引言中的问题
客人点菜命令的接收者,老板(大厨):
public class Receiver
{
public void BakeMutton()
{
Console.WriteLine("bake mutton");
}
public void BakeChickenWing()
{
Console.WriteLine("bake chickenwing");
}
}
点菜命令:
public abstract class Command
{
protected Receiver receiver;
public Command(Receiver receiver)
{
this.receiver = receiver;
}
abstract public void Execute();
}
class ConcreteCommand1 : Command
{
public ConcreteCommand1(Receiver receiver)
: base(receiver)
{ }
public override void Execute()
{
receiver.BakeMutton();
}
}
class ConcreteCommand2 : Command
{
public ConcreteCommand2(Receiver receiver)
: base(receiver)
{ }
public override void Execute()
{
receiver.BakeChickenWing();
}
}
增加一个服务生,负责记录客人点菜命令,并传达给大厨。点菜命令可以进行增加或取消操作。
public class Invoker
{
private IList<Command> commands = new List<Command>();
public void AddCommand(Command command)
{
commands.Add(command);
Console.WriteLine("增加订单" + command.ToString());
}
public void CancelCommand(Command command)
{
commands.Remove(command);
Console.WriteLine("取消订单" + command.ToString());
}
public void ExecuteCommand()
{
foreach (Command command in commands)
{
command.Execute();
}
}
}
客户端调用:
Receiver receiver = new Receiver();
Command command1 = new ConcreteCommand1(receiver);
Command command2 = new ConcreteCommand2(receiver);
Invoker invoker = new Invoker();
invoker.AddCommand(command1);
invoker.AddCommand(command2);
invoker.CancelCommand(command1);
invoker.ExecuteCommand();
六、优缺点及适用场景
优点:
比较容易的设计一个命令队列;在需要的情况下,可以比较容易的将命令计入日志;允许接收请求的一方决定是否要否决请求;比较容易的对命令实现撤销和重做;由于加入新的具体命令类不影响其他的类,因此增加新的具体命令类比较容易。
缺点:
可能会导致系统具有过多的具体命令类。
适用场景:
个人理解:基本上能表现其优点的地方都可以使用命令模式。