2012-06-17 2 views
11

Atomineer Utils의 Intellisense 및 Atomineer에 대한 Microsoft의 감사 ... 이러한 매개 변수는 모두 필요하며 변경할 수 없음입니다.13 개 매개 변수 생성자 개선

더 좋은 방법이 있나요?

/************************************************************************************************** 
* <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); 
+2

모든 컨테이너 객체에이 객체들을 모두 압축하여 대신 전달할 수는 없습니까? –

+1

구조체에 em을 넣고, 기본값을 주거나, 다른 것들을 기반으로하고, 필요한 것을 변경하고, 구조체를 전달하십시오. – chris

+0

@chris, 그냥 구조체의 생성자에 문제가 punts. 정말로 아무것도 바뀌지 않습니다. –

답변

33

귀하의 구체적인 사례를 살펴보면, 당신이 일을 크게 부 풀리지 않았다고 생각합니다.

개념적으로, 시스템의 문자가 있습니다

  • 의 이름을.
  • 기본 통계 (HP, 방어력 등)가 포함 된 통계 블록입니다.
  • 캐릭터의 2 차 속성 (경험치).
  • 잠재적 인 다른 것들 중에서 그들의 현재 주문 목록과 금을 포함하는 목록입니다.

매개 변수는 13 개가 아니라 4 개의 매개 변수입니다. 함수를 작성할 때 많은 수의 매개 변수가 사용되는 것을 볼 때 그 매개 변수 중 일부는 개념적으로 서로 연결되어있는 것이 좋습니다.그리고 확률은 다른 함수가 링크 된 매개 변수를 사용하고자하는 경우에도 유용합니다.

예를 들어, 캐릭터의 stat 블록을 표시하고자 할 수 있습니다. 이 작업을 수행하는 함수가 실제로 문자이 필요합니까? 아니; 그냥 stat 블록이 필요합니다. 그래서 stat 블록 객체를 취해야합니다.

캐릭터의 생성자와 같습니다.

+4

+1 Alan J Perlis가 말했듯이 : "10 개의 매개 변수가있는 프로 시저가 있다면 아마 일부를 놓친 것입니다." –

+0

당신의 요지를 보았습니다 만, "매개 변수를 객체로 교체"리팩터가 문제를 완화하지 않고 그냥 다른 위치로 옮깁니다. 이 생성자에서만 4가 될 수 있지만, 4 개의 클래스 매개 변수가 고려 될 때 여전히 13입니다. – Casey

+2

@Casey : 그럼? 4 클래스에 분산 된 13 개의 매개 변수는 생성자 당 평균 3.25 개의 매개 변수입니다. 생성자에 대해 4 개의 매개 변수를 갖는 데 문제가 있습니까? 4D 벡터 내적 함수가 8 개의 매개 변수를 사용한다고 생각하십니까? 아니; 그것은 2를 취하는데, 이것은 단지 각각 4 개의 값을가집니다. 다시 말하지만,이 기능에 관한 것이 아닙니다. 이는 데이터의 적절한 구성에 관한 것입니다. 4D 벡터는 생성자가 얼마나 많은 매개 변수를 취해도 * 하나의 객체 *입니다. 스탯 블록은 하나의 객체이기 때문에 아무리 많은 스탯도 포함되어 있습니다. –

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); 
    } 
}; 

그리고 속성은 AttrBase에서 상속 Attr 템플릿을 전문으로 만들 수있다.

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) {} 
}; 

이렇게하면 생성자의 복잡성을 높이 지 않고도 새 속성을 점진적으로 추가 할 수 있습니다. 또한, 동일한 속성 콜렉션이 다른 엔티티로 전달 될 수 있으며, 각각의 속성은 관심있는 속성에만 응답 할 수 있습니다. 속성의 서브 세트 만 설정할 필요가 있습니다. 속성의 존재 여부를 테스트하거나 기본값을 사용할 수 있습니다. 동적 속성을 추가 및 제거하려는 경우 컨테이너를 유지하기위한 추가 맵을 추가하여 컨테이너를 확장 할 수 있습니다.

+0

아래 투표에 의견을 말하십시오, 제발 고쳐야 할 것이 있습니다. 감사! – jxh

+2

-1 : 이것은 더 나쁩니다 *. 적어도 매개 변수가 많은 생성자에서는 매개 변수의 이름이 적당합니다. C++ 기본 유형으로 속성을 그룹화하는 것은 기능적으로 * 무의미합니다 *. 그룹으로 묶을 예정이라면, 실제로 뭔가를 의미하는 것으로하십시오. –

+2

복잡성을 줄이기 위해 아무 것도하지 않으며 더 모호하게 만듭니다. 'config'객체 나 args를 캡슐화하는 것을 전달하는 것이 낫습니다. – seand

1

더 좋은 방법은 Builder design pattern을 사용하는 것입니다. 또는 더 간단하게 현재 매개 변수에 대한 모든 매개 변수의 필드를 포함하는 클래스를 선언 할 수 있습니다. 매개 변수 클래스 자체는 필드를 적절한 기본값으로 초기화하는 생성자 (또는 생성자)를 가질 수 있으며 필드에 직접 액세스하여 값을 변경할 수 있습니다. 그런 다음 매개 변수 클래스에 함수를 구현하여 개체를 구성하거나 매개 변수 클래스의 인스턴스를 사용하는 개체 생성자를 정의하십시오.

관련 문제