web-dev-qa-db-ja.com

パブリック変数またはプライベート変数を使用する必要がありますか?

私は初めて大規模なプロジェクトを始めています。私にはたくさんのクラスがあり、それらのいくつかはパブリック変数を持ち、いくつかはセッターとゲッターメソッドを持つプライベート変数を持ち、同じものは両方のタイプを持っています。

主に1つのタイプのみを使用するように、このコードを書き直すことにしました。しかし、私はどちらを使用すべきかわかりません(同じオブジェクト内のメソッドにのみ使用される変数は常にプライベートであり、この質問の対象ではありません)。

パブリックとプライベートが何を意味するかという理論は知っていますが、実際の世界で何が使われているのですか?

31
Marek Čačko

privateデータメンバーは、カプセル化を提供するため、一般的に良いと見なされます。

ゲッターとセッターを提供するとカプセル化が解除されますが、publicデータメンバーよりも優れています。これは、そのデータへのアクセスポイントが1つしかないためです。

デバッグ中にこれに気付くでしょう。プライベートの場合、knowクラス内の変数のみを変更できます。パブリックの場合は、コードベース全体を検索してmightを変更する必要があります。

可能な限り、ゲッター/セッターを禁止し、プロパティprivateを作成します。これは情報隠蔽の原則に従います-クラスがどのプロパティを持っているかは気にするべきではありません。自己完結型である必要があります。もちろん、実際にはこれは現実的ではありません。もしそうなら、これに続く設計は、そうでないものよりも乱雑になり、保守が難しくなります。

もちろん、これは経験則です。たとえば、単純なポイントクラスにstruct(パブリックアクセスのclassと同等)を使用するだけです。

struct Point2D
{
   double x;
   double y;
};
33
Luchian Grigore

あなたは理論を知っていると言っており、他の答えはパブリック/プライベート、ゲッター、セッターの意味に掘り下げられているので、パブリック属性(C++のメンバーデータ)を作成する代わりにアクセサーを使用する理由に焦点を当てたいと思います。

ロジスティックプロジェクトにクラスTruckがあるとします。

_class Truck {
public:
    double capacity;

    // lots of more things...
};
_

北米人であれば、おそらくトラックの容量を表すためにガロンを使用するでしょう。 _Truck::capacity_の多くの直接的な使用は行われますが、プロジェクトが完成し、完全に機能すると想像してください。実際、あなたのプロジェクトは成功するので、あるヨーロッパの会社はあなたにプロジェクトを彼らに適応させるように頼みます。残念ながら、プロジェクトでは現在メートル法を使用する必要があるため、容量にガロンではなくリットルを使用する必要があります。

今、これは混乱する可能性があります。もちろん、1つの可能性は、北米専用のコードベースと、欧州専用のコードベースを準備することです。しかし、これは、バグ修正を2つの異なるコードソースに適用する必要があることを意味し、それは実行不可能であると判断されます。

解決策は、プロジェクトに構成の可能性を作成することです。ユーザーは、固定された固定されたガロンの選択ではなく、ガロンまたはリットルを設定できる必要があります。

上記のアプローチでは、これは多くの作業を意味し、_Truck::capacity_のすべての使用を追跡し、それらをどう処理するかを決定する必要があります。これはおそらく、コードベース全体に沿ってファイルを変更することを意味します。別の方法として、あなたはもっとtheoreticアプローチを決めたとしましょう。

_class Truck {
public:
    double getCapacity() const
        { return capacity; }

    // lots of more things...
private:
    double capacity;
};
_

可能な代替の変更には、クラスのインターフェースの変更は含まれません。

_class Truck {
public:
    double getCapacity() const
        { if ( Configuration::Measure == Gallons ) {
            return capacity;
          } else {
             return ( capacity * 3.78 );
          }
        }


    // lots of more things...
private:
    double capacity;
};
_

(これを行うには多くの方法があり、その1つは可能性の1つであり、これは単なる例であることに注意してください)

グローバルユーティリティクラス構成を作成する必要があります(ただし、とにかくそれを行う必要があります)、_truck.h_の_configuration.h_にインクルードを追加しますが、これらはすべてローカルの変更であり、コードベースの残りの部分です変更されないため、潜在的なバグを回避できます。

最後に、あなたはあなたが今大きなプロジェクトで働いていることも述べています。これは、これらの理由が実際にもっと意味のある分野だと思います。大規模なプロジェクトで作業する際に留意する目的は、保守可能なコード、つまり、新しい機能で修正および拡張できるコードを作成することです。個人的な小さなプロジェクトのゲッターとセッターについては忘れることができますが、私はそれらに慣れるようにします。

お役に立てれば。

16
Baltasarq

何がプライベート/パブリックまたは保護されるべきかに関して厳しい規則はありません。

それはあなたのクラスの役割とそれが提供するものに依存します。

  • クラスの内部動作を構成するすべてのメソッドとメンバーは、privateにする必要があります。
  • クラスが外部に提供するものはすべてpublicでなければなりません。
  • このクラスの特殊化で拡張する必要があるメンバーとメソッドは、protectedとして宣言できます。
5
HAL

OOPの観点から、ゲッター/セッターはカプセル化に役立ちます。したがって、常に使用する必要があります。クラスは外部に公開されません。

一方、C++の観点からは、値を取得/設定するだけでクラスが予期しないことをたくさん行うと、デメリットになる可能性もあります。一部のアクセスが大きなオーバーヘッドをもたらすか、単純かつ効率的であるかを知りたがります。パブリック変数にアクセスすると、何を取得するかが正確にわかります。ゲッター/セッターを使用すると、わかりません。

特に、小規模なプロジェクトのみを行う場合、変数名/型/ ...を変更するときにゲッター/セッターを記述し、それに応じてすべてを調整することに時間を費やすことは、ほとんど利益を得ずに多くのビジーワークを生み出します。その時間を費やして、役に立つ何かをするコードを書くほうがいいでしょう。

通常、C++コードは、実際のゲインを提供しない場合にゲッター/セッターを使用しません。可能な限り独立しなければならない多くのモジュールを含む1,000,000行のプロジェクトを設計するのは理にかなっているかもしれませんが、ほとんどの通常サイズのコードでは日々書くのはやり過ぎです。

3
sth

明確に指定されたデータを保持することが唯一の目的であるデータ型がいくつかあります。これらは通常、パブリックデータメンバーを持つ構造体として記述できます。それとは別に、クラスは抽象化を定義する必要があります。パブリック変数または些細なセッターとゲッターは、設計が十分に検討されていないことを示唆しているため、ほとんど何も抽象化しない弱い抽象化の集積が生じています。データについて考える代わりに、behaviorについて考えてください。このクラスはX、Y、Zを実行する必要があります。そこから、目的の動作をサポートするために必要な内部データを決定します。それは最初は簡単ではありませんが、データではなく、重要なのは振る舞いであることを思い出してください。

2
Pete Becker

主に上記の理由(カプセル化、適切に指定されたデータなど)のために、プライベートメンバー変数がパブリックメンバー変数よりも優先されます。また、外部エンティティが必要に応じてセッターの適切なチャネルを経由せずにメンバー変数を変更できないことを保証するため、データ保護も提供します。

ゲッターとセッターのもう1つの利点は、IDE(EclipseやNetbeansなど)を使用している場合、IDEの機能を使用してeveryを検索できることです。関数が呼び出されるコードベース。特定のクラスのデータの一部が使用または変更されている場所に関する可視性を提供します。また、内部ミューテックスを使用することで、メンバー変数へのアクセスをスレッドセーフにすることができます。セッター関数は、変数にアクセスまたは変更する前にこのミューテックスを取得します。

私は抽象化の支持者であり、それがまだ有用であるという点まで。抽象化のための抽象化は通常、その価値よりも複雑な混乱をもたらします。

1
codemaster91

通常、パブリック変数は推奨されません。より良い形式は、すべての変数をプライベートにし、ゲッターとセッターでそれらにアクセスすることです。

private int var;

public int getVar() {
  return var;
}

public void setVar(int _var) {
  var = _var;
}

Eclipseなどの最新のIDEは、「Implement Getters and Setters」や「Encapsulate Field」(変数のすべての直接アクセスを対応するgetterおよびsetter呼び出しに置き換える)などの機能を提供することでこれを支援します。

0
Stefan Seidel