8

さて、私が読んだほぼすべての場所で、ゲッター/セッターは「悪」であると読みました。さて、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 に制限されている場合はどうなりますか。

今私の実装は

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

では、ゲッター/セッターを使用せずに、他にどのようにこの制限を課すのでしょうか? ゲッター/セッターを使用せずにプロパティを変更するにはどうすればよいですか? ケース 1 では、armorValue を public メンバー変数にする必要があり、ケース 2 では getter/setter を使用する必要がありますか?

奇妙。みんなありがとう

4

8 に答える 8

17

あなたは何かを誤解しています。ゲッター/セッターを使用しないと、カプセル化が壊れて実装の詳細が公開され、悪の定義によっては「悪」と見なされる可能性があります。

適切なIDE/エディタのサポートがなければ、C++で書くのはやや面倒だという意味で、それらは悪と見なすことができると思います...

C++ の落とし穴の 1 つは、非 const 参照ゲッターを作成することです。これにより、変更も可能になります。これは、内部データへのポインターを返すことと同じであり、内部実装のその部分をロックします。実際には、フィールドを public にすることに勝るものはありません。

編集:コメントやその他の回答に基づいて、おそらく、すべてのフィールドに対して常に 非プライベートのゲッターとセッターを作成することを聞いたと思います。しかし、私はそれを悪とは呼びません。ただ愚かです ;-)

于 2013-01-26T18:03:28.963 に答える
11

少し逆張りです: はい、ゲッターとセッター (別名アクセサーとミューテーター)ほとんど悪です。

ここでの悪は、IMO ではなく、「カプセル化を破る」ことからではなく、int実際にはその型ではない変数を 1 つの型 (例: ) に定義することです。あなたの例を見ると、Armor を と呼んでいますが、int実際にはそうではありません。それは間違いなく整数ですが、とりわけint)範囲を定義する ではありません。あなたの型は整数ですが、まったく同じ範囲をサポートすることを意図したものではありませんintArmortype になりたい場合はinteger from 1 to 500、それを直接表す型を定義Armorし、その型のインスタンスとして定義します。この場合、強制したい不変条件は型自体の一部として定義されているため、

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 の (または少なくとも「1 つの」) 主な問題は、通常、変数を 1 つの型として定義したことを示していることです。いくつかの方法。

さて、一部の言語 (Java など) が、そのようなコードを記述するために必要なツールをプログラマーに提供していないことは事実です。ここで、C++ タグの使用は、あなたが本当に C++ を書きたいと思っていることを示していると信じています。C++ は必要なツールを提供します。(少なくとも IMO) コードは、C++ が提供するツールをうまく利用して、必要なセマンティック制約を適用しながら、クリーンで自然で読みやすい構文を使用する方が良いでしょう。

于 2013-01-26T19:02:34.103 に答える
5

要するに、彼らは悪ではありません。

内部表現を漏らさない限り、問題はありません。ここには問題はありません。

于 2013-01-26T18:03:41.620 に答える
1

ゲッターはいつでも悪です:

  1. クラスのデータメンバーに直接アクセスします
  2. クラスにデータを追加するたびに新しいゲッターを追加する必要がある場合
  3. ゲッターごとにデータの振る舞いが異なる

したがって、優れたゲッターは次のことを行います。

  1. リクエストを他のオブジェクトに転送するか、いくつかの場所からデータを収集します
  2. たった 1 つの getter を使用して大量のデータを取得できます
  3. フェッチするすべてのデータは同じ方法で処理されます

一方、セッターは常に悪です。

于 2013-01-26T18:31:22.843 に答える
1

ゲッター/セッターは問題ないようです。

getter/setter に代わる方法は、メンバー変数を public にすることです。より正確には、変数をメンバー関数なしで構造体にグループ化します。そして、クラス内でこの構造を操作します

于 2013-01-26T18:03:56.517 に答える
1

メンバーへのアクセスを許可するとカプセル化が減りますが、必要になる場合もあります。そして、それを行う最善の方法は、ゲッターとセッターを使用することです。一部の人々は、そのようなアクセスが必要ないときに、それが可能であり、それが習慣であるという理由だけでそれらを実装します。

于 2013-01-26T18:08:01.260 に答える
0

ゲッター/セッターを使用せずに、他にどのようにこの制限を課すことができますか? ゲッター/セッターを使用せずにプロパティを変更するにはどうすればよいですか?

変数から読み取った内容を確認し、その値が範囲外の場合は、代わりに定義済みの値を使用できます (可能な場合)。

変数の下のメモリを書き込みから保護する、書き込み試行をキャッチする、無効な値を持つものを許可しない/無視するなどの汚いハックに頼ることもできます。これは、実装するのが面倒で、実行するのに費用がかかります。ただし、デバッグには役立つ場合があります。

于 2013-01-26T18:08:06.570 に答える