现在的位置: 首页 > 综合 > 正文

SCSF – Part 9 The Command Design Pattern

2013年12月13日 ⁄ 综合 ⁄ 共 7898字 ⁄ 字号 评论关闭

Introduction

Part 8 of this series of articles concluded our discussion of services in the CAB.

系列的Part8总结了我们关于CAB里service的讨论。

This article and part 10 of this series will talk about commands in the CAB. Commands are a neat way of implementing the Command design pattern. This article will briefly recap what the Command pattern is and why it is useful. Part 10 will show how this is implemented in the CAB.

这篇文章以及part10会讨论 CAB里的commands,Commands是一个非常整洁的执行Command 设计模式的方法。

The Basics of the Command Pattern

‘Command’ is a design pattern from the original ‘Design Patterns’ book by Gamma, Helm, Johnson and Vlissides (the ‘Gang of Four’). The intent of the pattern is to:

“Encapsulate a request as an object, thereby letting you parameterize clients with different requests.”

The class diagram for this is below:

‘Command’  是 ‘Gang of Four’的设计模式中的一种, 这个模式的意图是: “将请求封装在一个对象里,根据不同的请求来确定客户。

 

Command Design Pattern

The Command Class and Interface

The diagram looks more difficult than it is. What it is saying is that we define a simple interface, ICommand, which always has just one method, Execute (with no parameters and no return value). We then implement this interface on various Command classes. So a Command is just a class that does something useful in response to an ‘Execute’ call. However, because all our commands implement Execute using the same interface we have polymorphism: we can use them interchangeably in client code without having to change the client code.

这图比其实际要复杂的多,他所说的是我们定义了一个简单的Interface:ICommand, 永远都只有一个方法:Execute (没有参数)我们在不同的Class里实现了这一接口,所以,一个Command只是再Execute里做一些有用的反应,因为所有我们的command 实现的Execute都是用了相同的接口。 这些Command有着多态的实现:我们可以用他来更换客户代码而不需要修改客户代码。

The Invoker

In the class diagram above the Invoker is just any code that calls the Execute method on a Command object through its ICommand interface. This will usually be done in a way that allows us to use the polymorphism discussed above. That is, we should be able to swap around which underlying Command object the Invoker is calling, without the Invoker having to change.

在以上类图里,Invoker 是任意通过ICommand  接口执行Command  里Execute 的代码。通常这些都可以通过以上讨论的多态来实现:我们应该能够任意的更换Invoker  调用的Command 对象,而不需要更改Invoker 。

The Receiver

In the simplest case the Execute method itself can just ‘be’ the command: it will do something useful. That may lead to our Command objects being very complicated however, so we may split out the underlying functionality into another class. This is the Receiver in the class diagram above. With a Receiver, whenever the Execute method is called on our Command it simply relays the call to the Receiver class which then does the work. If the command is complex there may be more than one Receiver class, with the Command class calling the Receivers as appropriate.

在这最简单的情况下,Execute 方法可以成为Command, 它将做一些有用的东西,那也许会使得我们的Command 对象变得非常复杂,然而,我们可以将潜在的功能放置到其他的类里去, 这就是图中的 Receiver ,通过Receiver , 无论何时,这个Command里德Execute 方法被调用的时候,它只是简单的将这调用传到Receiver ,尤Receiver做出相应的工作,如果这个command很复杂,也许会有复数个Receiver,由Command调用合适的Receivers

The Client

In the diagram above we also have the usual Gang of Four ‘Client’ class. This is code that gets us started by creating the other classes and hooking them up appropriately so that they will work. In real applications this may well be more than one class, but it makes the diagram neater to bucket all this functionality into one neat little box.

在以上类图里,我们还有个在 Gang of Four 里常见的‘Client’类,这是我们创建其他类并且适当的关联他们的地方,然后他们就能工作了,在真正的appplication里,也许这远不止一个class.不过这让类图显得十分干净。

In the Command pattern the client code will instantiate our Commands and Receivers and give the Command objects appropriate references to the Receiver objects.

在 Command pattern 里,这client code 将实力化我们的Commands 和Receivers  并且给于这个Command 对象一个合适的引用,

Finally note that in this pattern we are not passing any parameters to our Command objects, or returning any values from them. The method signature we are using is void Execute().

最后,注意在这一模式里,我们并没有传递任何参数到我们的Command对象里,或者返回任何值, 我们所用的方法签名是: Execute().

 

Why Is This Useful?

This pattern is useful because it decouples the code for actually executing a command from the code that calls the command code, providing a logical separation of duties and making the code easier to maintain.

这一模式很有用,因为它减弱了command里的代码, 它提供了一个逻辑上的职责分隔,而使得代码更容易维护。

Furthermore the pattern encapsulates the command logic in classes (the Receivers, if any, and the Command) that have a clearly defined interface. This lets us flexibly change which command we use in different circumstances using polymorphism.

此外,这一模式通过接口封装了类里的command 逻辑。这使得我们可伸展的根据环境更改我们的command.

For example we may have a class or set of classes that perform actions (our invokers), but want to vary those actions in a simple way based on the current state of the system. We can encapsulate the varying actions themselves into Command classes and then tell the invoker which one to use depending on the system state.

举例来说,我们也许有一个类或者一些类来执行一些行为(invokers),但是我们想通过一个简单的方法来多样化这些行为。我们可以将这些不同的行为封装到不同的类里,然后更具系统状态告诉invoker 去调用哪一个。

Menu Systems

The canonical example here, as discussed in the Design Patterns book, is a menu system in an application. The book describes how menu ‘toolkits’ are usually written as part of a framework, meaning that we need some way to allow a developer to write code to respond to menu events without having access to the menu code itself. We can do this by allowing the developer to write the commands and assign them to the Invokers (the menu items), without having to change the Invokers. Also, with menus we DO have the situation where we might want to swap around the commands that an Invoker is invoking.

这里有个权威的例子,正如设计模式这本书里讨论到的,一个用用程序里的菜单系统,这书告诉我们toolkits是怎样被写成framework的一部分的。意味着,我们需要一些方法,去允许一个开发者去写代码去反映menu events. 而不需要直接接触到menu本身的代码。我们可以允许开发者去写commands并且分配到Invokers(the menu items)。而不需要去更改Invokers。此外,我们提取额会碰到需要转移command的情况。

For example, we might have a File/New menu item. This might create a different sort of ‘new’ item depending on what screen the application was displaying. If the application was displaying a report it might create a new report; if the application was displaying a list of users it might create a new user; and so on. We could set this up so that the menu item was given a Command object and simply invoked it when File/New was selected. We could then have CreateNewReportCommand and CreateNewUserCommand objects that the client code would give to the menu item as the screens in the application changed. The menu itself wouldn’t then need any business logic, nor would the code behind the screen it was hosted on.

举例来说,我们也许有一个File/New menu ,根据不同的screen 我们可以创建不同功能的item ,如果这个application正在展示report,也许这按钮可以创建一个新的 report. 如果这个application 展现了一个users的 list. 它也许能创建一个新的user... 这个menu item这是简单的给出一个 command 当File/New被选中的时候。当creen 变化的时候,我们可以通过client code 给出 CreateNewReportCommand ,和CreateNewUserCommand 这菜单不需要任何业务逻辑,同样screen 后面的代码也不会被关联

.NET Delegates, .NET Events and the Command Pattern

It’s also worth bearing in mind that in many ways a simple use of a .NET delegate is a Command pattern, albeit a cumbersome one. The delegate itself is the command. It points to one or more methods in classes which are our Receivers. There will be some code to create the delegate and point it at the methods, which is the Client. Finally there will be some code to invoke the delegate (via the Invoke method), which is our Invoker.

Similarly .NET events, which are just special sorts of delegates, can be viewed as an implementation of the Command pattern.

This is fine, and of course very useful. But as we will see in part 10 the CAB gives us a more explicit way of using the pattern which is both simple and powerful.

值得铭记在心的事:一个简单的.net 的delegate 是一个 Command pattern,尽管它不是很灵活,代理本身就是command. 他所指的一个或多个类里的classes 是我们的Receivers,client code 创建了delegate 并将它指向一些方法。最终Invoker会激发这delegate ,时间是特殊的delegates,可以被看做是Command pattern的执行。当然这是非常有用的,但是在part10,我们会看到CAB会给我们许多更清晰,更简单,更有效地方法去使用这些模式

 

.NET Menu Systems and the Command Pattern

Menu systems are a key use for the Command pattern as far as the Gang of Four are concerned. Normally in the .NET framework we use events for hooking up menu and toolbar items to underlying code. As discussed above, this can be regarded as an implementation of the Command pattern. However, the CAB implementation of the Command pattern is specifically intended to be used for menu systems and to replace the normal approach. We will examine the benefits it gives in part 10.

Menu systems are 是使用Command pattern 的关键,通常情况下,在.net framework里,我们使用events 去关联menu和toolbar. 正如以上所讨论到的,我们可以视之为Command patten的实现。然而在CAB里特地为Menu systems实现,并且会替换普通的方式,我们会在后面解释它的好处。

References

Data and Object Factory Page on the Command Pattern
http://www.dofactory.com/Patterns/PatternCommand.aspx

‘Gang of Four’ Book: Design Patterns: Elements of Reusable Object-Oriented Software
http://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional/dp/0201633612/ref=sr_1_1/104-5057575-3250306?ie=UTF8&s=books&qid=1185705878&sr=1-1

‘Head First Design Patterns’ (excellent book, although Java-based):
http://www.amazon.com/Head-First-Design-Patterns/dp/0596007124/ref=pd_bbs_sr_3/104-5057575-3250306?ie=UTF8&s=books&qid=1185706020&sr=1-3

抱歉!评论已关闭.