11

感谢 Microsoft 的 Intellisense 和 Atomineer 的 Atomineer Utils...所有这些参数都是必需的和不可变的。

有一个更好的方法吗?

/**************************************************************************************************
 * <summary>Initializes a new instance of the ADTBattleCharacter class.</summary>
 * <param name="name">         The name of the character.</param>
 * <param name="max_HP">       The maximum hit points.</param>
 * <param name="max_MP">       The maximum magic power.</param>
 * <param name="strength">     The strength.</param>
 * <param name="agility">      The agility.</param>
 * <param name="attack_power"> The attack power.</param>
 * <param name="defense_power">The defense power.</param>
 * <param name="gold">         The gold carried by the character.</param>
 * <param name="experience">   The experience the character is worth.</param>
 * <param name="stop_resist">  The character's resistance to stopspell.</param>
 * <param name="sleep_resist"> The character's resistance to sleep.</param>
 * <param name="hurt_resist">  The character's resistance to hurt/hurtmore.</param>
 * <param name="spell_list">   Available spells.</param>
 **************************************************************************************************/
ADTBattleCharacter(std::string name, unsigned char max_HP, unsigned char max_MP,
                   unsigned char strength, unsigned char agility,
                   unsigned char attack_power, unsigned char defense_power,
                   unsigned short gold, unsigned short experience,
                   double stop_resist, double sleep_resist, double hurt_resist,
                   std::bitset<SPELL_MAX> spell_list);
4

3 回答 3

33

看看你的具体情况,在我看来你没有很好地解决问题。

从概念上讲,系统中的角色具有:

  • 一个名字。
  • 一个统计数据块,包含他们的基本统计数据(HP、防御等)。
  • 角色的次要属性(经验)。
  • 一个清单,其中可能包括他们当前的法术列表和他们的黄金,以及其他可能的东西。

那是 4 个参数,而不是 13 个。当你编写一个函数时,你看到它需要大量的参数,很可能其中一些参数在概念上是相互关联的。其他函数想要使用这些链接参数的可能性也很大。

例如,您可能想要显示一个角色的统计数据块。这样做的功能真的需要字符吗?不; 它只需要 stat 块。所以它应该需要一个统计块对象。

就像角色的构造函数一样。

于 2012-06-17T02:53:46.867 回答
1

更好的方法是使用Builder 设计模式。或者,更简单地说,您可以声明一个类,其中包含当前构造函数的所有参数的字段。参数类本身可以有一个构造函数(或多个构造函数),将字段初始化为合理的默认值,您可以通过直接访问字段来更改值。然后要么在参数类中实现一个函数来构造你的对象,要么定义一个接受参数类实例的对象构造函数。

于 2012-06-17T02:46:40.230 回答
0

如果目标只是减少提供给构造函数的参数数量,有很多方法可以实现。真正的问题是,正如我从第一篇文章的评论中了解到的那样,是否有更简单的方法来管理参数。

使参数更易于管理的一种方法是使用通用数据结构来维护它们。地图之类的东西。

enum AttrTag { AT_Name, AT_Max_HP, AT_Max_MP, //...
               AT_Spells };

struct Attributes {
    typedef std::unique_ptr<AttrBase> AttrPtr;
    typedef std::map<AttrTag, AttrPtr> AttrMap;
    AttrMap attributes;

    template <AttrTag TAG>
    typename Attr<TAG>::value_type get_attr () const {
        AttrMap::const_iterator i = attributes.find(TAG);
        if (i != attributes.end()) return i->second->attr_cast<TAG>()->value;
        return Attr<TAG>::default_value;
    }

    template <AttrTag TAG>
    void set_attr (typename Attr<TAG>::value_type value) {
        attributes[TAG] = AttrPtr(new Attr<TAG>(value));
    }

    bool has_attr (AttrTag t) const {
        return attributes.find(t) != attributes.end();
    }

};

它会像这样使用:

Attributes attrs;
attrs->set_attr<AT_Gold>(100);
//...
ADTBattleCharacter(attrs);
//...
unsigned short g = attrs->get_attr<AT_Gold>();

AttrBase属性将从知道如何委派给实际属性的类中脱落。

template <AttrTag> struct Attr;

struct AttrBase {
    virtual ~AttrBase () {}
    template <AttrTag TAG> Attr<TAG> * attr_cast () {
        return dynamic_cast<Attr<TAG> *>(this);
    }
};

并且属性将通过专门AttrAttrBase.

template <AttrTag TAG>
struct Attr : public AttrBase {
    typedef unsigned char value_type;
    enum { default_value = 0 };
    value_type value;
    Attr (value_type v) : value(v) {}
};

template <>
struct Attr<AT_Name> : public AttrBase {
    typedef std::string value_type;
    static std::string default_value;
    value_type value;
    Attr (value_type v) : value(v) {}
};

template <>
struct Attr<AT_Gold> : public AttrBase {
    typedef unsigned short value_type;
    enum { default_value = 1 };
    value_type value;
    Attr (value_type v) : value(v) {}
};

这允许在不增加构造函数的复杂性的情况下逐步添加新属性。此外,可以将相同的属性集合传递给不同的实体,每个实体只能对它们感兴趣的那些属性做出反应。只需要设置属性的子集。可以测试属性的存在,也可以使用默认值。如果要添加和删除动态属性,可以通过添加额外的地图来扩展容器来执行此操作。

于 2012-06-17T02:41:35.037 回答