37

私は初めて大きなプロジェクトをやっています。私には多くのクラスがあり、そのうちのいくつかにはパブリック変数があり、一部にはセッターとゲッターメソッドを持つプライベート変数があり、両方のタイプがあります。

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

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

4

7 に答える 7

40

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

それらに getter と setter を提供するとカプセル化が破られますが、publicそのデータへのアクセス ポイントは 1 回しかないため、データ メンバーよりも優れています。

デバッグ中にこれに気付くでしょう。プライベートの場合、クラス内の変数のみを変更できることがわかります。公開されている場合は、コードベース全体を検索して、変更された可能性がある場所を探す必要があります。

可能な限り、getter/setter を禁止し、プロパティを作成しますprivate。これは、情報隠蔽の原則に従います。クラスが持つプロパティを気にする必要はありません。自己完結型である必要があります。もちろん、実際にはこれは実現可能ではありません。もしそうなら、これに従う設計は、そうでない設計よりも雑然として維持するのが難しくなります。

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

struct Point2D
{
   double x;
   double y;
};
于 2013-01-18T13:28:16.167 に答える
19

あなたは理論を知っていると言い、他の答えはパブリック/プライベート、ゲッター、セッターの意味を掘り下げたので、パブリック属性(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 つの可能性にすぎないこと、およびこれは単なる例であることを考慮してください)

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

最後に、あなたは現在、大きなプロジェクトに取り組んでいると述べていますが、それは、これらの理由が実際により理にかなっているような分野だと思います. 大規模なプロジェクトで作業する際に念頭に置いておくべき目的は、保守可能なコード (つまり、新しい機能で修正および拡張できるコード) を作成することです。個人的な小さなプロジェクトではゲッターとセッターのことは忘れてもかまいませんが、私はそれらに慣れるように努めます。

お役に立てれば。

于 2013-01-18T13:51:52.533 に答える
12

何をプライベート/パブリックにするか、または保護するかについて、厳密なルールはありません。

クラスの役割と提供する内容によって異なります。

  • クラスの内部動作を構成するすべてのメソッドとメンバーは、privateにする必要があります。
  • クラスが外部に提供するものはすべてパブリックにする必要があります。
  • このクラスの特殊化で拡張する必要があるメンバーとメソッドは、 protectedとして宣言できます。
于 2013-01-18T13:50:08.020 に答える
4

OOP の観点からは、getter/setter はカプセル化に役立つため、常に使用する必要があります。ゲッター/セッターを呼び出すと、クラスはバックグラウンドで必要なことを実行でき、クラスの内部は外部に公開されません。

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

特に小規模なプロジェクトのみを行う場合、ゲッター/セッターの作成に時間を費やし、それに応じて変数名/タイプ/を変更することに決めたときにそれらをすべて調整します...ほとんど利益のない多くの忙しい作業が発生します。その時間を何か役に立つコードを書くことに費やしたほうがいいでしょう。

C++ コードでは、通常、実際の利益が得られない場合、getter/setter を使用しません。できるだけ独立しなければならない多数のモジュールを含む 1,000,000 行のプロジェクトを設計する場合、それは理にかなっているかもしれませんが、通常のサイズのコードのほとんどは、日常的に書くとやり過ぎです。

于 2013-01-18T14:08:00.997 に答える
3

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

于 2013-01-18T14:00:28.803 に答える
1

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

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

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

于 2013-01-18T16:36:08.883 に答える
1

通常、パブリック変数は推奨されません。すべての変数をプライベートにして、getter と setter でアクセスすることをお勧めします。

private int var;

public int getVar() {
  return var;
}

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

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

于 2013-01-18T13:29:04.243 に答える