【问题标题】:How to Implement a Decision Table in Objective-C如何在 Objective-C 中实现决策表
【发布时间】:2014-09-13 23:14:18
【问题描述】:

我是一名新手程序员,我刚刚开始阅读有关决策表的内容。我已经阅读了 Code Complete 中的第 18 章,它很有启发性。我环顾网络,试图在 Objective-C 中找到任何类型的决策表示例,但我找不到任何样板文件或如何实现这一点的真实世界示例。

我在业余时间用 Objective-C 编写游戏,我一直在处理日益复杂的游戏规则。有一些嵌套比较深的 if-else 语句,以及一些已经有 10 个或更多案例需要处理的 switch 语句。我认为使用决策表会更容易,但我不知道如何在 Objective-C 中为诸如游戏逻辑之类的不平凡的事情实现这一点。

例如,我需要不同的方法来执行不同的状态组合。我将如何在 Objective-C 中实现一个决策表,它可以将不同的状态组合作为键,并根据它们的组合运行特定的逻辑?

【问题讨论】:

标签: objective-c logic decision-tree control-structure


【解决方案1】:

好吧,我对 Objective-C 中的决策表进行了更多思考,并提出了实现基本决策表的解决方案。我不会在这里发布整个代码,只是让决策表工作的 sn-ps 及其基本用途。如果您想查看完整的代码以及如何改进它的一些很好的建议,我将其发布在Code Review SE。我现在发布这个是因为有人发表了评论要求我这样做,但我肯定会最终改进这一点并整合评论中的建议。无论如何,这是代码。

首先在初始化方法之前,我建立了一些 NSString 常量,它们将用作 NSDictionary 中的键。

//Two options for the decision table, either access the dictionary directly with 0-x, the enum values, or make strings for their names
//the advantage of strings is that it is more extensible, and the position in the enum doesnt matter
NSString* const kEnemyMovementStateJustSpawned = @"enemyMovementStateJustSpawned";
NSString* const kEnemyMovementStateIdle = @"enemyMovementStateIdle";
NSString* const kEnemyMovementStateNeedsMoving = @"enemyMovementStateNeedsMoving";
NSString* const kEnemyMovementStateToFloor = @"enemyMovementStateToFloor";
NSString *const kEnemyMovementStateAtDestinationFloor = @"enemyMovementStateAtDestinationFloor";
NSString* const kEnemyMovementStateToFloorExit = @"enemyMovementStateToFloorExit";
NSString* const kEnemyMovementStateToAttackWalls = @"enemyMovementStateToAttackWalls";
NSString* const kEnemyMovementStateToAttackFloor = @"enemyMovementStateToAttackFloor";
NSString* const kEnemyMovementStateToAttackRoom = @"enemyMovementStateToAttackRoom";

然后我使用这些常量以及类中的方法名称来构建 NSDictionary:

-(void) setupDecisionTable {
    //the string objects are the names of methods in the class
    _decisionTable = @{kEnemyMovementStateJustSpawned: @"doEnemyJustSpawned",
                       kEnemyMovementStateIdle: @"doEnemyIdle",
                       kEnemyMovementStateNeedsMoving: @"doEnemyNeedsMoving",
                       kEnemyMovementStateToFloorExit: @"doFloorMovement",
                       kEnemyMovementStateToFloor: @"doVerticalMovement",
                       kEnemyMovementStateAtDestinationFloor: @"doEnemyAtDestinationFloor",
                       kEnemyMovementStateToAttackWalls: @"doFloorMovement",
                       kEnemyMovementStateToAttackFloor: @"doFloorMovement",
                       kEnemyMovementStateToAttackRoom: @"doFloorMovement"
                       };
}

然后每打勾我就调用这个方法,它使用从字典中拉取的对象的名字来执行方法:

-(void) doMovement {
    //the selector is formed from a string inside the decision table dictionary
    SEL methodToCallName = NSSelectorFromString([_decisionTable objectForKey:[self stringForState:self.state]]);
    if (methodToCallName) {
        IMP functionPointer = [self methodForSelector:methodToCallName];
        void (*methodToCall)(id, SEL) = (void *)functionPointer;
        methodToCall(self, methodToCallName);
    }
}
-(NSString *) stringForState:(EnemyMovementState)state {
    switch (state) {
        case EnemyMovementStateJustSpawned:
            return kEnemyMovementStateJustSpawned;
        case EnemyMovementStateIdle:
            return kEnemyMovementStateIdle;
        case EnemyMovementStateNeedsMoving:
            return kEnemyMovementStateNeedsMoving;
        case EnemyMovementStateToFloor:
            return kEnemyMovementStateToFloor;
        case EnemyMovementStateAtDestinationFloor:
            return kEnemyMovementStateAtDestinationFloor;
        case EnemyMovementStateToFloorExit:
            return kEnemyMovementStateToFloorExit;
        case EnemyMovementStateToAttackWalls:
            return kEnemyMovementStateToAttackWalls;
        case EnemyMovementStateToAttackFloor:
            return kEnemyMovementStateToAttackFloor;
        case EnemyMovementStateToAttackRoom:
            return kEnemyMovementStateToAttackRoom;
        default:
            return nil;
    }
}

最后这里是几个执行的方法,只是一个完整的例子:

-(void) doEnemyIdle {
    if ([self checkFloorsForJobs]) {
        self.state = EnemyMovementStateNeedsMoving;
    } else {
        [self doIdleMovement];
    }
}
-(void) doEnemyNeedsMoving {
    [self calculateFloorExitPositionByFloor];
    self.state = EnemyMovementStateToFloorExit;
}

这是一个非常简单的实现。目前它只能处理一个输入,一个更好的决策表将能够评估多个输入并提供适当的输出。我认为可以通过使用将状态与其他变量结合起来从字典中选择正确对象的中间方法来扩展它。

在完成所有这些之后,我不确定决策表是否值得在 Objective-C 中付出努力。我不知道代码是否比 switch 语句更容易理解。为了向代码中添加新逻辑,它必须在比 switch 语句似乎需要的更多地方进行修改。我提供此代码作为示例,如果有人有其他版本的决策表,那么在 Objective-C 中查看其他版本的决策表会很酷。

【讨论】:

    猜你喜欢
    • 2013-05-29
    • 2020-02-03
    • 2017-05-02
    • 1970-01-01
    • 1970-01-01
    • 2011-03-25
    • 1970-01-01
    • 2011-04-14
    • 2011-09-14
    相关资源
    最近更新 更多