Objective-C 的状态机库
这个库受到了 Ruby 钻石 state_machine 的启发。
WIP(请,读:您找出它,然后告诉我)
git submodule
。让我们对一个订阅类进行建模
此时,您负责定义一个状态属性,如下所示。在未来,这将由 StateMachine 处理
@interface Subscription : NSObject
@property (nonatomic, retain) NSString *state; // Property managed by StateMachine
@property (nonatomic, retain) NSDate *terminatedAt;
- (void) stopBilling;
@end
这里是精彩的部分。在类的实现中,我们使用 StateMachine DSL 定义有效的状态和事件。对于每个事件,您定义有效的转换。
DSL 是一个正在进行中的项目,将会改变
您还必须在构造函数中调用 initializeStateMachine
,目前是这样。目标是移除这个限制并减少干扰。
@implementation Subscription
STATE_MACHINE(^(LSStateMachine *sm) {
sm.initialState = @"pending";
[sm addState:@"pending"];
[sm addState:@"active"];
[sm addState:@"suspended"];
[sm addState:@"terminated"];
[sm when:@"activate" transitionFrom:@"pending" to:@"active"];
[sm when:@"suspend" transitionFrom:@"active" to:@"suspended"];
[sm when:@"unsuspend" transitionFrom:@"suspended" to:@"active"];
[sm when:@"terminate" transitionFrom:@"active" to:@"terminated"];
[sm when:@"terminate" transitionFrom:@"suspended" to:@"terminated"];
[sm before:@"terminate" do:^(Subscription *subscription){
subscription.terminatedAt = [NSDate dateWithTimeIntervalSince1970:123123123];
}];
[sm after:@"suspend" do:^(Subscription *subscription) {
[subscription stopBilling];
}];
});
- (id)init {
self = [super init];
if (self) {
[self initializeStateMachine];
}
return self;
}
- (void) stopBilling {
// Yeah, sure...
}
@end
StateMachine 将为您的方法添加触发事件。为了使编译器快乐,您需要告诉它在运行时会有这些方法。您可以通过定义具有一个方法(每个事件一个)和 initializeStateMachine
方法的 Objective-C 类别的头文件来实现这一点。就像这样
@interface Subscription (State)
- (void)initializeStateMachine;
- (BOOL)activate;
- (BOOL)suspend;
- (BOOL)unsuspend;
- (BOOL)terminate;
- (BOOL)isPending;
- (BOOL)isActive;
- (BOOL)isSuspended;
- (BOOL)isTerminated;
- (BOOL)canActivate;
- (BOOL)canSuspend;
- (BOOL)canUnsuspend;
- (BOOL)canTerminate;
@end
如您所见,StateMachine 将定义查询方法来检查对象是否处于某个状态(isPending, isActive 等)以及是否可以触发有效转换(canActivate, canSuspend 等)。
现在,您可以使用通常的方式创建类的实例
Subscription *subscription = [[Subscription alloc] init];
它的初始状态是 pending
subscription.state; // @"pending"
您可以触发事件
[subscription activate]; // retuns YES because it's a valid transition
subscription.state; // @"active"
[subscription suspend]; // retuns YES because it's a valid transition
// Method stopBilling was called
subscription.state; // @"suspended"
[subscription terminate]; // retuns YES because it's a valid transition
subscription.state; // @"terminated"
subcription.terminatedAt; // [NSDate dateWithTimeIntervalSince1970:123123123];
如果我们触发一个无效的事件
// The subscription is now suspended
[subscription activate]; // retuns NO because it's not a valid transition
subscription.state; // @"suspended"