Robotlegs和AS3-Signals之间可以很好地协作,两者运用一致的面向对象原则来达到它们不同的目标。Signals非常适合用来自动地实现依赖注入。Signals结合Robotlegs可以在应用程序框架层完全摆脱Flash事件机制。摆脱事件机制意味着消除了基于字符串注册的事件机制的不明确性,Signals提供了强类型的观察者模式。
使用Robotlegs的MVCS框架和AS3的事件可以实现不同Actors之间的通讯,Model和Service发出事件来触发Command,实现这一切的核心是事件。为了在MVCS框架内使用Signals必须创建一种扩展机制注册Signals,像注册Command那样,这就是SignalCommandMap。
SignalCommandMap扩展标准的MVCS Context成为SingalContext。SignalContext提供了SignalCommandMap,SignalCommandMap可以映射Signal类或实例到Command,Singnal的dispatch方法调用后Command就会被执行,dispatch传递的数据和对象也会注入到Command内部。
让我们看一个简单的SignalCommandMap示例来了解一下它是如何运作的。
这是一个从列表里面添加和移除的食物的示例,选择的食物的总价会显示出来。我们先来看一下继承自SignalContext的Context类。
SignalCafeContext启动应用程序
1 public class SignalCafeContext extends SignalContext 2 { 3 override public function startup():void 4 { 5 injector.mapSingleton(FoodOrderModel); 6 injector.mapSingleton(FoodOrderUpdatedSignal); 7 injector.mapSingleton(FoodItemAddedSignal); 8 9 signalCommandMap.mapSignalClass(AddFoodItemSignal, AddFoodItemToOrderCommand); 10 signalCommandMap.mapSignalClass(FoodItemSelectedSignal, FoodItemSelectedCommand); 11 signalCommandMap.mapSignalClass(RemoveAllSignal, RemoveAllSelectedItemCommand); 12 signalCommandMap.mapSignalClass(NoFoodItemSelectedSignal, NoFoodItemSelectedCommand); 13 14 mediatorMap.mapView(FoodSelectionView, FoodSelectionViewMediator); 15 mediatorMap.mapView(FoodOrderView, FoodOrderViewMediator); 16 mediatorMap.mapView(FoodOrderSummaryView, FoodOrderSummaryViewMediator); 17 mediatorMap.mapView(FoodItemRemovalView, FoodItemRemovalViewMediator); 18 } 19 }
SignalContext的结构和标准的MVCS Context完全一样。重写startup()方法启动应用程序。差别在于原来我们把事件注册到Command,而现在我们把Signals注册到Command。
在SignalCafeContext中注册了4个Signals到相应的Command,这些Signals继承于基础Signal类。你可能使用命名注入,但是很快会被用什么字符串困扰,避免字符串是个好的选择,有助于利用编译器帮你检查出类型错误。
强类型的Signal很简单,它包含一个构造函数没有附加的方法和属性。你可以扩展Signals来添加方法和属性,但是在这个示例中不需要。SignalCommandMap接受任何实现了ISignal接口的类,让我们看看Command是怎样被触发的。
AddFoodItemToOrder触发了AddFoodItemToOrderCommand
1 public class AddFoodItemToOrder extends Signal 2 { 3 public function AddFoodItemToOrder() 4 { 5 super(FoodType); 6 } 7 }
就像前面说的那样,这个类不复杂。注意这里调用super(FoodType),Signals构造函数参数被用来确定Signals传递的参数的类型和数量,调用dispatch(itemType)方法把参数传递给了Command。
FoodSelectionViewMediator绑定了一个视图,当用户点击“Add Some Food”按钮时Mediator会派发一个带有itemType数据的Signal。
1 public class FoodSelectionViewMediator extends Mediator 2 { 3 [Inject] 4 public var view:FoodSelectionView; 5 6 [Inject] 7 public var addItem:AddFoodItemSignal; 8 9 override public function onRegister():void 10 { 11 view.itemTypeAdded.add(handleItemTypeAdded); 12 } 13 14 protected function handleItemTypeAdded(itemType:FoodType):void 15 { 16 addItem.dispatch(itemType); 17 } 18 }
当AddFoodItemSignal被派发时,AddFoodItemToOrderCommand就会调用。
1 public class AddFoodItemToOrderCommand extends SignalCommand 2 { 3 [Inject] 4 public var itemType:FoodType; 5 6 [Inject] 7 public var model:FoodOrderModel; 8 9 override public function execute():void 10 { 11 model.addItemToOrder(itemType); 12 } 13 }
AddFoodItemToOrderCommand有两个注入的public属性,itemType属性是FoodType对象这正是AddFoodItemSignal构造方法中定义的参数,AddFoodItemSignal包含的FoodType对象实例会被注入到AddFoodItemToOrderCommand。这里我们还注入了在SignalCafeContext中注册为单例的FoodOrderModel实例。
注意,通过Signal dispatch方法传递的参数将立即被注册,当command执行过后会立即被注销。
AddFoodItemToOrderCommand调用FoodOrderModel的addItemToOrder方法,并且将Signal传递过来的参数传过去。 这个示例包含了在Robotleg中使用SignalCommandMap的基本方法,没有包含的内容建议查阅SignalCommandMap单元测试套件,里面包含了在view和model内部使用Signal通信的示例。
KevinChu
2013-7-3