簡體   English   中英

C ++ Getter / Setter(替代品?)

[英]C++ Getter/Setter (Alternatives?)

好吧,就在我讀到的每個地方,我都讀到了吸氣劑/孵化器是“邪惡的”。 現在,作為一個經常在PHP / C#中使用getter / setter的程序員,我看不出他們是如何活着的。 我已經讀過他們打破了封裝等等,但是,這是一個簡單的例子。

class Armor{

  int armorValue;
public:
  Armor();
  Armor(int); //int here represents armor value
  int GetArmorValue();
  void SetArmorValue(int);
};

現在,讓我們說吸氣劑和制定者是“邪惡的”。 如何在初始化后更改成員變量?

例:

Armor arm=Armor(128); //armor with 128 armor value

//for some reason I would like to change this armor value
arm.SetArmorValue(55); //if i do not use getters / setters how is this possible?

讓我們說無論出於何種原因,上述情況都不合適。 如果我的游戲將護甲值限制在1到500之間怎么辦?(沒有護甲可以擁有超過500護甲或少於1護甲的護甲)。

現在我的實施成了

void Armor::SetArmor(int tArmValue){
      if (tArmValue>=1 && tArmValue<=500)
         armorValue=tArmValue;
      else
         armorValue=1;
}

那么,如果不使用getter / setter,我將如何施加此限制? 如果不使用getter / setter,我還能如何修改屬性? armorValue應該是案例1中的公共成員變量,還是案例2中使用的getter / setter?

好奇。 多謝你們

你誤會了什么。 使用getter / setter會打破封裝並暴露實現細節,並且對於某些邪惡定義可能被視為“邪惡”。

我猜他們在某種意義上可以被認為是邪惡的,如果沒有適當的IDE /編輯器支持,他們在某種程度上是用C ++編寫的tediois ...

C ++的一個缺陷是創建非const引用getter,它也允許修改。 這與返回指向內部數據的指針相同,並將鎖定內部實現的那部分,並且實際上並不比將字段公開更好。

編輯:基於評論和其他答案,您聽到的內容可能是指始終每個字段創建非私有的getter和setter。 但我也不會稱之為邪惡,只是愚蠢;-)

稍微逆勢:是的,getter和setter(又名存取函數)大多邪惡的。

這里的邪惡不是IMO,而是來自“打破封裝”,因為從簡單地將變量定義為一種類型(例如, int )時,它根本就不是那種類型。 看看你的例子,你將Armor稱為int ,但事實並非如此。 雖然它無疑是一個整數,但它肯定不是一個int ,它(除其他外)定義了一個范圍。 雖然你的類型是一個整數,但它根本不打算支持與int相同的范圍。 如果希望Armor的類型integer from 1 to 500 ,請定義直接表示的類型,並將Armor定義為該類型的實例。 在這種情況下,由於您要強制執行的不變量被定義為類型本身的一部分,因此您無需在其上添加setter以嘗試強制執行它。

template <class T, class less=std::less<T> >
class bounded {
    const T lower_, upper_;
    T val_;

    bool check(T const &value) {
        return less()(value, lower_) || less()(upper_, value);
    }

    void assign(T const &value) {
        if (check(value))
            throw std::domain_error("Out of Range");
        val_ = value;
    }

public:
    bounded(T const &lower, T const &upper) 
        : lower_(lower), upper_(upper) {}

    bounded(bounded const &init) 
        : lower_(init.lower), upper_(init.upper), val_(init.val_)
    { }

    bounded &operator=(T const &v) { assign(v);  return *this; }

    operator T() const { return val_; }

    friend std::istream &operator>>(std::istream &is, bounded &b) {
        T temp;
        is >> temp;

        if (b.check(temp))
            is.setstate(std::ios::failbit);
        else
            b.val_ = temp;
        return is;
    }
};

有了這個,定義一些范圍為1..500的護甲變得完全無足輕重:

bounded<int> armor(1, 500);

根據具體情況,您可能更喜歡定義(例如) saturating類型,其中嘗試分配超出范圍的值很好, 實際分配的值將只是范圍內的最近值。

saturating<int> armor(1, 500);

armor = 1000;

std::cout << armor;  // prints "500"

當然,我上面給出的內容也有點勉強。 對於你的護甲類型,支持可能很方便-= (並且可能是+= )因此攻擊最終會像x.armor -= 10;

底線:getter和setter的(或至少“一個”)主要問題是它們通常指向你已經將變量定義為一種類型,當你真的想要一些其他類型的碰巧類似於幾種方式。

現在,某些語言(例如,Java)確實無法為程序員提供編寫這樣的代碼所需的工具。 在這里,我相信你使用C ++標簽來表明你確實想要編寫C ++。 C ++確實為您提供了必要的工具,並且(至少IMO)您的代碼將更好地利用它提供的工具,因此您的類型強制執行所需的語義約束,同時仍然使用干凈,自然,可讀的語法。

簡而言之:它們不是邪惡的。

只要它們不泄漏內部表示,它們就沒有錯。 我覺得這里沒問題。

對get / set函數的一個常見批評是它們可能被客戶端代碼濫用以執行邏輯上應該封裝在類中的操作。 例如,假設一個客戶想要“擦亮”他們的盔甲,並決定效果是將“價值”增加20,所以他們做他們的小事和設定的事情並且很高興。 然后其他地方的其他客戶端代碼決定生銹的裝甲應該將值降低30,並且他們做了他們的位。 與此同時,客戶代碼中的其他十幾個地方也允許對裝甲進行拋光和生銹效果 - 以及說“加固”和“開裂”,並直接實施。 這沒有中央控制......盔甲類的維護者沒有能力做這樣的事情:

  • 具有防銹,拋光,增強和裂縫效果,每件盔甲最多適用一次

  • 調整為特定邏輯效果添加或減去值的數字

  • 決定新的“皮革”盔甲類型不會生銹,並忽略客戶試圖讓它這樣做

另一方面,如果想要制作盔甲生銹的第一個客戶不能通過界面這樣做,他們會去裝甲班的維護者並說“嘿,給我一個功能來做這個”,然后其他人可以開始使用邏輯級“生銹”操作,如果它以后變得有用,我可以在盔甲類中輕松地集中實現它們(例如,通過使用單獨的布爾值來說明盔甲是生銹的,或者記錄銹效的單獨變量)。

因此,具有get / set函數的東西是它們阻礙了邏輯功能的API的自然演變,而不是在整個客戶端代碼中分配邏輯,導致極端情況陷入無法維護的混亂。

你的getter / setter看起來不錯。

getter / setter的替代方法是將成員變量公開。 更准確地說,將變量分組到沒有成員函數的結構中。 並在您的班級內運行此結構

訪問成員可以減少封裝,但有時候這是必要的。 最好的方法是通過吸氣劑和制定者。 有些人在沒有必要這樣的訪問時實現它們,只是因為它們可以而且這是一種習慣。

無論何時,吸毒者都是邪惡

  1. 他們直接訪問該類的數據成員
  2. 每次向類添加數據時都必須添加新的getter
  3. 每個getter中的數據行為都不同

好的吸氣者因此會做以下事情:

  1. 他們將請求轉發給其他對象或從多個地方收集數據
  2. 您只需使用一個getter即可獲取大量數據
  3. 您獲取的所有數據都以相同的方式處理

另一方面,塞特斯總是邪惡的。

如果不使用getter / setter,我怎么能施加這個限制呢? 如果不使用getter / setter,我還能如何修改屬性?

您可以檢查從變量中讀取的內容,如果其值超出范圍,則使用預定義值(如果可能)。

您還可以使用臟的黑客攻擊,例如保護變量下面的內存不會寫入,捕獲寫入嘗試以及禁止/忽略具有無效值的內存。 這實現起來很麻煩並且執行起來很昂貴。 但是,它可能對調試很有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM