Eug*_*y89 4 flash design-patterns actionscript-3
只是好奇你们如何解决封装命令的问题.您是否为每个命令创建一个单独的类?或者还有另一种方式(没有大量的课程)?
请注意,我正面临着动作脚本3的问题.
更新:更确切地说,我想知道如何组织命令相关的机器(例如每个命令的类).
先感谢您!
小智 9
命令模式是Java缺乏高阶函数(无法传递对函数的引用)的掩盖.在AS /其他ES语言中使用此模式毫无意义,因为此处不存在此问题.
非常不幸的是,学术界最近使用Java进行CS研究,特别是如果CS不是你的专业.这可以解释这个和其他Java-isms移植到其他语言没有任何批判性分析.
命令模式是关于分离三个不同类别的对象之间的关注点:
正如wvxvw所指出的那样,通常意味着你有一个实现的TON类ICommand实际上只是作为代理来调用Receiver上的方法- 这是Java所必需的.随着时间的推移,这会变得有点难以管理.
但是让我们看看一些代码,我将遵循引入此处命令模式基础知识的示例代码,但为了清晰起见略有简化:
所以首先是接收器:
// Receiver
public interface IStarShip {
function engage():void;
function makeItSo():void;
function selfDestruct():void;
}
public class Enterprise implements IStarShip {
public function Enterprise() { }
public function engage():void {
trace(this, "Engaging");
}
public function makeItSo():void {
trace(this, "Making it so");
}
public function selfDestruct():void {
trace(this, "Self Destructing");
}
}
Run Code Online (Sandbox Code Playgroud)
和调用者:
// invoker
public class CaptPicard {
private var _command:ICommand;
public function CaptPicard() { }
public function set command(cmd:ICommand):void {
this._command = cmd;
}
public function issueCommand():void {
}
}
Run Code Online (Sandbox Code Playgroud)
最后一些命令:
// command
public interface ICommand {
function execute():void;
}
public class EngageCommand implements ICommand
{
private var receiver:IStarShip
public function EngageCommand(receiver:IStarShip) {
this.receiver = receiver;
}
public function execute():void {
receiver.engage();
}
}
public class SelfDestructCommand implements ICommand
{
private var receiver:IStarShip
public function SelfDestructCommand(receiver:IStarShip) {
this.receiver = receiver;
}
public function execute():void {
receiver.selfDestruct();
}
}
public class MakeItSoCommand implements ICommand
{
private var receiver:IStarShip
public function MakeItSoCommand(receiver:IStarShip) {
this.receiver = receiver;
}
public function execute():void {
receiver.makeItSo();
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以通过以下方式来解决这些问题:
var enterprise:Enterprise = new Enterprise;
var picard:CaptPicard = new CaptPicard();
picard.command = new SelfDestructCommand(enterprise);
picard.issueCommand();
Run Code Online (Sandbox Code Playgroud)
到目前为止,它与示例代码紧密相关,并且是ActionScript中命令模式的非常标准的实现.但是,现在我们有三个ICommand实现,并且随着接收器可以增加的数量增加,编排模式所需的命令数量也会增加.
如果我们开始检查Command本身,除了告诉接收器做一些工作之外,它并没有做太多其他事情.正如wvxvw暗示的那样,动作脚本中已经有了这样的功能:一流的功能.
让我们看看可能的实现,以减少你需要浮动的ICommand的实现数量,而不需要改变你的模式.
让我们说我们制作了一个通用类型的命令,让我们说:
public class GenericCommand implements ICommand {
private var worker:Function;
public function GenericCommand(worker:Function) {
this.worker = worker;
}
public function execute():void {
this.worker.call();
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我们的新类型仍然实现ICommand,但它不是直接绑定到某个实现,而是接受一个worker来做一些工作.它不会立即执行它,它只是坚持它并等待其他东西使它运动.
然后我们可以将代码切换为这样的代码:
var enterprise:Enterprise = new Enterprise;
var picard:CaptPicard = new CaptPicard();
picard.command = new GenericCommand(function() { enterprise.selfDestruct(); });
picard.issueCommand();
picard.command = new GenericCommand(function() { enterprise.engage(); });
picard.issueCommand();
picard.command = new GenericCommand(function() { enterprise.makeItSo(); });
picard.issueCommand();
Run Code Online (Sandbox Code Playgroud)
有了这个GenericCommand,我们可以将所有命令展开到这个新模式中(或者在它们之间混合和匹配).
但是如果你仔细观察,你可以看到我们通过引用封闭的变量将一个通用命令紧密地耦合到IStarShip enterprise,或许更令人担心的是如果我们不小心我们可能会创建大量这些关闭.它们都需要在某些时候进行垃圾收集,这可能会影响性能,或者更糟糕的是导致内存泄漏.
我们可以将这一层更多地分离,使其更具动态性.enterprise我们可以使用工厂模式来帮助动态生成命令,而不是直接关闭局部变量.考虑一下:
public class StarShipCommandFactory {
private var worker:Function;
public function StarShipCommandFactory(worker:Function) {
this.worker = worker;
}
public function to(receiver:IStarShip):ICommand {
return new GenericCommand(function() {
worker.call(undefined, receiver);
});
}
}
Run Code Online (Sandbox Code Playgroud)
然后我们可以使用它来创建一个命令工厂来创建这些命令.就像是:
var enterpriseA:Enterprise = new Enterprise();
var enterpriseB:Enterprise = new Enterprise();
var picard:CaptPicard = new CaptPicard();
var selfDestuctor:StarShipCommandFactory = new StarShipCommandFactory(function(starShip:IStarShip):void {
starShip.selfDestruct();
} );
var blowUpA:ICommand = selfDestructor.to(enterpriseA);
var blowUpB:ICommand = selfDestructor.to(enterpriseB);
picard.command = blowUpA;
picard.issueCommand();
picard.command = blowUpB;
picard.issueCommand();
Run Code Online (Sandbox Code Playgroud)
这将减少需要生成的静态类的数量,以利用属性第一类函数的动态创建的对象,但仍然应用相同的一般概念.
实际上,使用这种模式,您可以构建非常复杂的命令,代理多个接收器上的多个动作,这可能是一个非常强大的功能.
ICommand当时的传统实现?坚持传统模式的最大原因之一是易于序列化.因为对象是显式的,所以它们很容易序列化.所以,假设你有一堆Vector.<ICommand>.您可以轻松地序列化它们,将它们写出来,然后再重新加载它们并按顺序重放它们,并且应该处于与您完全相同的状态.动态生成的对象就像我之前描述的对象一样有点棘手 - 不是不可能,只是比较棘手.
如果你担心维护大量的ICommands映射到接收器动作,那么在过去我使用元编程来解决这个问题.使用ruby/python解析一定数量的文件,并自动生成ICommand映射.它们很多时候都是相当天真的实现,它们是自动化的主要候选者.
无论如何,这些是我对这个问题的看法.你可以做很多事情来帮助简化你的代码 - 我刚刚触及了表面.您的里程可能会有所不同 - 请记住:"找到解决问题的模式,而不是反过来" - 但也许您可以从中收集一些有用的信息.
| 归档时间: |
|
| 查看次数: |
1729 次 |
| 最近记录: |