首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我是不是违反了OOP设计准则?几个有趣的设计泡菜

我是不是违反了OOP设计准则?几个有趣的设计泡菜
EN

Stack Overflow用户
提问于 2012-10-14 18:00:45
回答 1查看 196关注 0票数 2

我正在为我正在开发的一个游戏设计一个新的启动系统。它是一个侧面滚动条,加电显示为圆形物体,玩家必须触摸/移动才能获得他们的加电。然后通电被激活,并在几秒钟后自行停用。每次上电都有自己定义的持续时间。为了简单起见,电源每X秒产生一次(显示在屏幕上)。

我创建了一个PowerUpManager,这是一个单例,它的工作是决定何时创建新的通电,然后将它们放置在哪里。

然后,我创建了Powerup基类,并为每个新的Powerup创建了一个继承自该基类的类。每次启动都可以处于以下三种状态之一:禁用、放置在屏幕上和由玩家拾取。如果玩家没有拿起电源,而是继续移动,电源将退出屏幕,并且应该从放置状态返回到禁用状态,因此可以再次放置。

我提出的一个要求是,当我编写一个新的加电类时,应该有最少的代码更改。我最多只能做一段代码:PowerUpManager的构造函数,其中您必须将新的加电添加到容纳所有加电的容器中:

代码语言:javascript
复制
PowerupManager::PowerupManager()
{
    available = {
        new PowerupSpeed(),
        new PowerupAltWeapon(),
        ...
    };
}

PowerUpManager,更详细地说(问题来了!):保存一个指向调用available的PowerUp (基类)的指针向量。这是一个初始的容器,保存了游戏中每个加电的副本。为了处理不同的状态,它有两个列表:一个保存指向当前加电的指针,另一个保存指向当前活动加电的指针。它还有一个方法,可以在每个游戏的节拍中调用,决定是否以及在哪里放置新的加电,并清理未被拾取的加电。最后,它有一个方法,当玩家遇到加电时调用该方法,该方法激活加电(将其从放置列表移动到活动列表,并调用加电的激活方法)。

最后,一旦你了解了全部情况,问题就来了:我需要一种方法来让客户端代码询问某个特定的加电当前是否处于活动状态。例如:玩家有一件武器,但有一个暂时替代该武器的加电。当我轮询输入并识别出玩家想要射击他的武器时,我需要调用正确的射击方法--替代武器启动射击方法,而不是常规的武器射击方法。

我想了一下这个特殊的需求,然后想出了这个:

代码语言:javascript
复制
template <typename T>
T* isActivated() // Returns a pointer to the derived Powerup if it exists in the activated list, or nullptr if it doesn't
{
    for(Powerup *i : active) // Active is a list of currently active power ups
    {
        T *result = dynamic_cast<T*>(i);

        if(result)
            return result;
    }

    return nullptr;
}

因此,客户端代码如下所示:

代码语言:javascript
复制
PowerUpAltWeapon *weapon = powerUpManager->isActivated<PowerUpAltWeapon>();
if(weapon)
    ...

我认为解决方案是优雅和整洁的,但本质上它是试图将基类型转换为派生类型。如果这不起作用,您可以尝试下一个派生类型...一个很长的if / else if链,它只是伪装在一个循环中。这是否违反了我刚才描述的准则?不是在if / else if的长链中将一个基类型强制转换为它的所有派生类型,直到你得到一个命中?有没有其他的解决方案?

第二个问题是:有没有一种方法可以消除在PowerupManager构造函数中构造所有不同的电源的需要?如果你想要引入一种新的电源,那是目前你唯一需要做改变的地方。如果我能摆脱它,那就很有趣了。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-10-14 18:44:46

这是基于您的设计的,但是如果是我,我会为客户端中的每个PowerUp和一组ID选择一个ID,并且每当用户拥有一个PowerUp时,该ID将被添加到它的集合中,并且...剩下的你都知道了。使用此技术,我可以快速查找每个PowerUp并避免dynamic_cast

代码语言:javascript
复制
std::set<PowerUp::ID> my_powerUps;
template< class T > bool isActivated() {
    return my_powerUps.find( T::id() ) != my_powerUps.end();
}

关于你的第二个问题,我有一个类似的程序,它加载一些插件,而不是PowerUp,我有一个纯虚拟基类,它包含了插件所需的所有方法,并在共享模块中实现它,然后在启动时,我从一个特定的文件夹加载它们。例如,每个共享模块都包含一个create_object,它返回一个plugin* (在您的示例中当然是PowerUp* ),然后我迭代该文件夹,加载模块并调用create_object以从它们创建插件并将它们注册到我的plugin_manager

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12881156

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档