2012-06-17 28 views
11

Cảm ơn Microsoft dành cho Intellisense và Atomineer cho Utine Atomineer ... Tất cả các tham số này là bắt buộc và không thay đổi.Cải tiến trên một hàm tạo 13 tham số

Có cách nào tốt hơn để thực hiện việc này không?

/************************************************************************************************** 
* <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

Bạn không thể đóng gói tất cả vào một số đối tượng chứa và vượt qua thay vào đó? –

+1

Đặt em vào một cấu trúc, đưa ra các giá trị mặc định hoặc căn cứ vào một số khác, thay đổi cái bạn cần và chuyển cấu trúc vào? – chris

+0

@chris, mà chỉ punts vấn đề để các nhà xây dựng của cấu trúc. Không thực sự thay đổi bất cứ điều gì. –

Trả lời

33

Nhìn vào trường hợp cụ thể của bạn, có vẻ như với tôi rằng bạn chưa chia nhỏ mọi thứ.

Về mặt lý thuyết, một nhân vật trong hệ thống của bạn có:

  • Một tên.
  • Một khối thống kê, chứa số liệu thống kê cơ bản (HP, quốc phòng, v.v.).
  • Thuộc tính phụ của nhân vật (trải nghiệm).
  • Khoảng không quảng cáo, bao gồm danh sách phép thuật hiện tại và vàng của họ, trong số những thứ có thể khác.

Đó là 4 tham số, chứ không phải 13. Khi bạn đang viết hàm, và bạn thấy rằng nó đang lấy một số lượng lớn tham số, tỷ lệ cược tốt là một số tham số được liên kết với nhau.Và tỷ lệ cược cũng tốt rằng các chức năng khác sẽ muốn sử dụng các thông số được liên kết đó.

Ví dụ: bạn có thể muốn hiển thị khối thống kê của một ký tự. Chức năng thực hiện điều này có thực sự cần ký tự không? Không; nó chỉ cần khối stat. Vì vậy, nó phải mất một đối tượng khối stat.

Giống như hàm tạo của ký tự.

+4

+1 Như Alan J Perlis nói: "Nếu bạn có một thủ tục với mười tham số, có thể bạn đã bỏ lỡ một số." –

+0

Tôi thấy quan điểm của bạn, nhưng trình thay thế "Thay thế tham số với đối tượng" không làm giảm bớt vấn đề, chỉ cần di chuyển nó đến một vị trí khác. Nó chỉ có thể là 4 trong constructor này, nhưng khi những tham số của 4 lớp được đưa vào tài khoản, nó vẫn còn 13. – Casey

+2

@Casey: Vì vậy? 13 tham số trải rộng trên 4 lớp là trung bình 3.25 tham số cho mỗi hàm tạo. Có một vấn đề với việc có 4 tham số cho một constructor? Bạn có xem xét chức năng chấm điểm vector 4D để lấy 8 tham số không? Không; nó mất 2, mà chỉ xảy ra để có 4 giá trị trong mỗi. Một lần nữa, nó không chỉ là về * chức năng này *; đó là về tổ chức dữ liệu thích hợp. Một vector 4D là * một đối tượng *, bất kể có bao nhiêu tham số mà các nhà xây dựng của nó thực hiện. Cũng giống như một khối stat là một đối tượng duy nhất, không có vấn đề bao nhiêu số liệu thống kê trong đó. –

0

Nếu mục tiêu chỉ là giảm số lượng đối số được cung cấp cho hàm tạo, có nhiều cách để đạt được điều đó. Câu hỏi thực sự là, khi tôi hiểu nó từ các bình luận cho bài viết đầu tiên của tôi, là nếu có một cách dễ dàng hơn để quản lý các tham số.

Một cách để làm cho các thông số dễ quản lý hơn là sử dụng cấu trúc dữ liệu chung để duy trì chúng. Một cái gì đó giống như một bản đồ.

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

}; 

Và nó sẽ được sử dụng như thế này:

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

Các thuộc tính sẽ đi ra khỏi lớp AttrBase đó sẽ biết làm thế nào để uỷ thác cho các thuộc tính thực tế.

template <AttrTag> struct Attr; 

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

Và thuộc tính sẽ được tạo ra từ một mẫu chuyên Attr được thừa kế từ AttrBase.

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

Điều này cho phép các thuộc tính mới được bổ sung thêm mà không làm tăng độ phức tạp của hàm tạo. Ngoài ra, cùng một tập hợp các thuộc tính có thể được chuyển cho các thực thể khác nhau và mỗi thuộc tính có thể chỉ phản ứng với các thuộc tính quan tâm đó. Chỉ cần thiết lập một tập hợp con các thuộc tính. Sự hiện diện của một thuộc tính có thể được kiểm tra, hoặc một giá trị mặc định có thể được sử dụng. Nếu bạn muốn thêm và xóa thuộc tính động, vùng chứa có thể được mở rộng để làm như vậy bằng cách thêm một bản đồ bổ sung để giữ chúng.

+0

Xin vui lòng bình luận về một cuộc bỏ phiếu xuống, xin vui lòng, vì vậy tôi biết những gì để sửa chữa. Cảm ơn! – jxh

+2

-1: Đây là * tồi tệ hơn *. Ít nhất với hàm tạo với nhiều tham số, các tham số có tên hợp lý. Các thuộc tính nhóm theo kiểu cơ bản C++ của chúng là hàm * vô nghĩa *. Nếu bạn định nhóm chúng lại, hãy thực hiện nó bằng một cái gì đó thực sự có ý nghĩa gì đó. –

+2

Nó không làm bất cứ điều gì để giảm sự phức tạp và làm cho nó mơ hồ hơn. Tốt hơn là chuyển đối tượng 'config' hoặc thứ gì đó đóng gói các arg. – seand

1

Cách tốt hơn là sử dụng Builder design pattern. Hoặc, đơn giản hơn, bạn có thể khai báo một lớp có chứa các trường cho tất cả các tham số cho hàm tạo hiện tại của bạn. Lớp tham số có thể có một hàm tạo (hoặc các hàm tạo) để khởi tạo các trường thành các giá trị mặc định hợp lý, và bạn thay đổi các giá trị bằng cách truy cập trực tiếp các trường. Sau đó, hoặc là thực hiện một hàm trong lớp tham số để xây dựng đối tượng của bạn, hoặc định nghĩa một hàm tạo đối tượng để lấy một cá thể của lớp tham số.

Các vấn đề liên quan