javascript - 如何在任务系统中构建/设计事件和任务以使代码易于管理?

标签 javascript oop design-patterns event-handling observer-pattern

我正在创建一个 Javascript 游戏,为用户提供任务来玩。每个任务都有许多任务,当满足某些要求时这些任务就会完成。以下是我最初打算采用的设计。

enter image description here

如您所见,每个 TaskGameEvent(简化为 Event)都有一个类型和一些数据(封装在一个字典中) .当一个事件被发送到 QuestManager 时,它被传递给事件的 Quest 对象,这些对象又将它传递给每个假定其类型的 Task是相同的。然后针对事件中的相关数据 测试任务中的每个要求。我不做 1:1 检查的原因是因为一个事件可能有额外的数据。

例如 data{item: someItem, locationFound: someLocation} != requirement{item: someItem}

这在最大限度地减少需要创建的类数量方面非常有效。事件和任务是通用的,因此无需创建大量子类即可轻松创建和测试它们。

但是这种设计产生了一个问题。由于它的普遍性,如果不先找到相同类型的事件并检查发送给它的数据,就永远无法确定应该给任务什么要求。随着项目的扩展,这将成为管理的噩梦。

相反,我可以为 EventTask 创建涵盖各种类型的子类,如下所示:

Event -> ItemPickupEvent, MoveEvent, etc.
Task -> ItemPickupTask, ItemPickedUpAtLocationTask, MoveTask, etc.

但它们之间的数据相似,似乎非常没有必要。

我最后的想法是创建数据对象来封装某些事件类型传递的数据,如下所示:

ItemPickupData、MoveData、TalkData 等

事件和任务可以只被赋予适当的数据对象。这为正在使用的数据提供了更好的结构。如果一条数据不应该成为需求,它可以简单地默认为空。

就可维护性和结构设计而言,这是一个合适的解决方案还是有更好的方法来解决这个问题?

谢谢。

最佳答案

Because of its generality, it is never certain what requirements should be given to a task without first finding an event of the same type and checking the data being sent to it.

据我了解,问题是在事件对象和任务对象中复制了几乎相同的数据。

例如,您有 Event { 'type': 'ItemPickup', data: { 'name': 'MagicSword', 'kind': 'weapon' } }

然后你想添加一个任务来拾取魔剑,你创建了 Task { 'type': 'ItemPickup', data: { 'name': 'MagicSword' } } 。 所以这就是问题所在,在这里您需要查找事件配置的准确程度,并将相同的数据放入任务对象中。

我认为将这些数据移动到单独的对象中的解决方案应该很有效。 另一件看起来不对的事情是你有 type 字段,它暗示你需要有子类。 如果您创建像 ItemPickupDataMoveData 等数据对象,这也会得到解决。

另一种方法是让 Event 本身成为这个数据对象,并有类似这样的东西(伪代码):

class Event // base class for events with common data and methods

// the subclasses can be almost empty
class ItemPickupEvent extends Event  
class MoveEvent extends Event

class Task
    _requirements = [
        new ItemPickupEvent('MagicSword'),
        // and maybe it is even better to wrap events into "Requirment" objects, 
        // which can, for example, be marked as completed
        new Requirement(new MoveEvent('OldForest')),
        ...
    ]

然后您可以通过这种方式管理需求:

class Task
    isComplete(event)
        complete = false
        // go over requirements to see if this task is complete
        for requirement in this._requirments:
           complete = complete && requirement->isComplete(event)
        return complete

class Requirement
    isComplete(event)
        # check event class and properties to understand if the requirement is satisfied
        if class(event) == class(this._event):
            if event.isNameMatches(this._event):
               this->_complete = true
        return this->_complete

也可以在不检查类名的情况下完成。 这个想法是让 Requirement 基类对每个事件类都有特殊的方法,并默认拒绝它们。 然后子类可以处理特定的事件类型:

class Requirement
    isComplete(event)
        // redirect the type detection to event object
        return event->isComplete(this)

    isCompleteItemPickup(event)
        return false

    isCompleteMove(event)
        return false

class ItemPickupRequirement
    isCompleteItemPickup(event)
        // here we know that event is ItemPickupEvent
        if event.isNameMatches(this._event):
               this->_complete = true
        return this->_complete

class MoveRequirement
    isCompleteItemPickup(event)
        // here we know that event is MoveEvent
        if event.isNameMatches(this._event):
               this->_complete = true
        return this->_complete

Requirement 类的isComplete 方法从Task 类中使用,它将类型检测重定向到事件对象。 然后事件对象将自身传递回要求的适当方法:

class Event
    isComplete(requirement) // should be implemented in subclasses

class ItemPickupEvent
    isComplete(requirement)
        // here we call the specific requirement method
        // now we know the exact event object type (it is ItemPickupEvent)
        return requirement->isCompleteItemPickup(this)

class MoveEvent
    isComplete(requirement)
        return requirement->isCompleteMove(this)

结构可能看起来有点复杂,但根据具体情况,您可能需要 Requirement 类及其子类(例如,可以有通用的 ItemPickupRequirement 和一些特定的 PowerItemPickupRequirement)。

关于javascript - 如何在任务系统中构建/设计事件和任务以使代码易于管理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37948215/

相关文章:

javascript - 为什么我的正则表达式中缺少一个字符?

javascript - PIXI.js 的 Closure Compiler EXTERNS - 自定义对象参数注释

javascript - 动态设置 ng-model 被破坏

c++ - 为什么我应该更喜欢使用成员初始化列表?

oop - 用于解析文本文件的面向对象设计模式?

rest - 如何设计一个查询,从中检索要以 RESTful 方式应用过滤器的资源的最后数据?

javascript - 我可以在 mocha 输出中隐藏失败详细信息吗?

java - 二叉树的大小方法

java - 抽象类以摆脱 Activity 中的冗余代码

python - 使用 pytest 管理测试数据的正确方法是什么?