質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.38%

privateをつけるかどうか(初学者です)

解決済

回答 5

投稿

  • 評価
  • クリップ 3
  • VIEW 2,541

score 5

まず、大学の先生に質問するべき内容をこのサイトでするのは場違いですが, 
あまりにも先生に対して日頃の不信感があるので質問させてください.

先生が「データ隠蔽を実現して,プログラムの品質を向上させるために, クラス内のフィールドは,原則として非公開(private)にしよう.」と言っていました.
Java初学者なのですが, それが非常に疑問です.

例えばCarクラスというものを作ったとすると以下のように,
車のいる座標や, ナンバーなどの特有の情報は隠蔽する必要があると思いますが,
車種, 車幅といった基本的な車の情報を隠蔽する理由が分かりません.

御教授の程よろしくお願いします. 

プログラム例

class Car {

String name;
int width;
int height;
int length;
double fuelCapacity;   //タンク容量
double fuelExpenses;   //燃費

private String number;
private double positionX;
private double positionY;
private double remainFuel;  //残り燃料

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+13

もしこれがScalaやKotlin、または、全く違うC#であったら、別にpublicでも良いのですが、Javaに限って言えば、インスタンスフィールドにprivate以外は設定すべきでありません。クラス外への公開する場合はgetterやsetter経由のみにし、直接フィールドへのアクセスさせるべきではありません。なぜなら、Javaは後から細かく変更できないからです。

まず、フィールドへのアクセス権は必ず「読み取り」と「書き換え」がセットになっており、それぞれ別々に制御できません。privateに設定すれば、クラス外は読み取りも書き換えもできなくなりますし、publicに設定すればどこからでも読み取りだけでなく書き換えも可能になってしまいます。また、読み取りはpublicでいいが書き換えはprotectedにしたいと言ったこともできません。finalを付ければ書き換えは防げますが、今度はコンストラクター以外では一切書き替えできなくなってしまいます。

そういった問題を回避するために、つまり「読み取り」と「書き換え」を別々に制御するには、getterやsetterを使う必要があります。getterとsetterは別々のメソッドであるため、別々のアクセス権を設定することができますし、全く実装しないという選択もできるからです。

さて、「読み取り」も「書き換え」もpublicなアクセス権にする場合は、getterとsetterを用意せずにフィールド自体をpublicにしてもいいと思うかも知れません。しかし、将来もアクセス権はずっと同じにすると言うことがあるのでしょうか?最初の設計では書き込みもpublicでいいと思っていたけど、実際に作って行くと、他から自由に書き換えられると思わぬバグがでてくるからprivateにした方が良いということは起きないと言い切れないのでしょうか?そうです、フィールドを一度publicにしてしまうと後から柔軟なアクセス権が将来にわたってできなくなってしまうのです。

その都度getterとsetterに書き換えてやればいいと思うかも知れません。ですが、それは自分のクラスの都合です。既に他のクラスで使われている場合、その全てでフィールドアクセスをgetterやsetterに書き換えてやる必要があります。修正漏れを起こす可能性も高いですし、ましてや、ライブラリとして公開している場合、互換性が無いかなり大きな変更になってしまいます。フィールドアクセスを許すと言うことは、後からどのような変更もしないという覚悟を持たない限り、やって良いものではありません。

getterやsetterにはフィールドにはないもう一つ利点があります。それは単にフィールドを読み取ったり書き換えたりすること以外の動作を追加することもできると言うことです。たとえばfuealCapacityに負の値を入れたらおかしな事が起きます。しかし、フィールドへの代入では負の値を防ぐことはできません。それこそNaNやInfinityだって代入できてしまいます。ですが、これがsetterであれば負の値とかの場合は例外を出して弾くとかができます。また、getterも内部のフィールドを変更しても動作を変えずと言うのもできます。位置をx,y座標として記憶していたが、r,偏角として持った方が良いという場合が出てきたとします。getterでxを与えるだけの場合はrと偏角からその都度求めれば良いですが、xをフィールドにしてしまうと、そのようなことができなくなります。将来の内部変更もgetterやsetterであれば柔軟に対応できるということです。

このようにフィールドへのアクセスは、将来の変更に対して強い障壁になります。privateであれば自クラスのみ考えれば良いのに対し、一度public等にすると他クラスについても大きな変更を強いることになってしまいます。よほど特殊な状況でない限り、Javaのインスタンスフィールドは常にprivateにしておいた方が無難です。※

※staticなフィールドではそうとは限らないと言うことに注意してください。例えば、クラスの定数をpublic static finalにする(これはこれで問題があるのだが)等が考えられます。


【おまけ】

これはJavaだけの話です。Java以外のScalaやKotlin、C#など現代的な言語(21世紀生まれの言語)では「プロパティ」という機能があり、フィールドアクセスよりも柔軟に対応できます。(JavaにもPropertyという機能がありますが、これは全く別の物です。)

「プロパティ」を簡単に言えばフィールドへのアクセスのように使えるgetterやsetterです。x.namex.name = "hoge"と書いた場合、Javaではフィールドへのアクセスであり、アクセス権は必ずどちらも同じであり、メソッドのような計算した値を返したり、範囲チェックや追加の処理をしたりすることはできません。「プロパティ」へのアクセスは同じように書きますが、実際はメソッド(関数)として動作をカスタマイズできます。そればかりか単純getterやsetterの動作で言い場合は、省略した書き方もできるようになっています。Javaのように単純なgetterやsetterでもたくさん書かなければならないと言うこともありません(Lombokや一部のフレームワークを使えばアノテーションのみで生成とかできますが)。

ですので「常にprivate」という話はJava以外だと通用しません。他言語を触るときに何も考えずにprivateにしてしまうと、Javaの呪縛から抜け出せないかわいそうな人と思われますので、気をつけてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+3

車種・車幅を取得したい場合はフィールドをpublicにするのでなく、
車種・車幅を取得するためのメソッド(getter/setterと呼ばれます)を準備するのが定石となっています。

これが定石になっている理由として、
・車の車種は読み取り専用で、外部から変更できないようにする(getterのみを準備)
・例えば、車幅を外部から設定したい場合に、setterメソッドに「3m未満はエラーとする」というような妥当性チェックをすることができる
などのメリットがあります。

オブジェクト指向でプログラムを書く場合のお作法に近いものではありますが、
実際、メソッドの量が冗長になってしまうなど、いくつかのデメリットはあります。。

外部へのリンクとなり申し訳ないのですが、
以下のページが詳しいので参考になさってはいかがでしょうか。
https://qiita.com/katolisa/items/6cfd1a2a87058678d646

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+3

車種, 車幅といった基本的な車の情報を隠蔽する理由が分かりません.

後から書き換える必要が無く、
そして隠蔽する理由も無いのであれば、次のように書いてしまうのもアリだと考えます。

class Car {
    ...

    public final double 車幅;
    public final String 車種;

    public Car(..., double 車幅, String 車種) {
        ...
        this.車幅 = 車幅;
        this.車種 = 車種;
    }
}

先生が「データ隠蔽を実現して,プログラムの品質を向上させるために, クラス内のフィールドは,原則として非公開(private)にしよう.」と言っていました.
Java初学者なのですが, それが非常に疑問です.

一般論として正しいです。
フィールドは全てprivateにして、適宜アクセサを用意します。

ただ、jackal_さんの言うように本来隠蔽しなくて良いものを隠蔽しているのも事実です。
私見ですが、Javaがプロパティを言語レベルでサポートしたら前段の一般論は崩れると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

まず、サンプルがおかしいです。
別にCarクラスを作っても構いませんが、
質問者さん(が感じた)ように意味が理解できない場合が多いです。

OOP等を参考にしてみてください。

これらを参考にして考えると、「オブジェクトだけがデータ(とその変化)および処理を知っている」という状態にできます。

できる限りオブジェクトだけが知っている状態にするため、よほどのことがなければフィールドはprivateにします。

ただし、定数( Javaでは常にどこかのクラスに属していなければならないっていうアレで ) 等のような場合はやむを得ないですが、基本的にはprivate.


[追記0]

ちなみに、すべてpublicにしてしまうとC言語での「グローバル変数」と何ら変わりはありません。
(アクセスするときの書き方が違うだけ)

C言語ですら、グローバル変数は非推奨です。

「グローバル変数 危険性」とかでggってみてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

あなたが公開すべきと思ってるものはpublicにしましょう。
ましかし、外部から車種、車幅を変更できるようにする、というのもなんぼなんでもやばいでしょうし、
そこんところは外部からは変更不可にしとくべきじゃないでしょうか

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.38%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る