まず、大学の先生に質問するべき内容をこのサイトでするのは場違いですが,
あまりにも先生に対して日頃の不信感があるので質問させてください.
先生が「データ隠蔽を実現して,プログラムの品質を向上させるために, クラス内のフィールドは,原則として非公開(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; //残り燃料
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
もしこれが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.name
やx.name = "hoge"
と書いた場合、Javaではフィールドへのアクセスであり、アクセス権は必ずどちらも同じであり、メソッドのような計算した値を返したり、範囲チェックや追加の処理をしたりすることはできません。「プロパティ」へのアクセスは同じように書きますが、実際はメソッド(関数)として動作をカスタマイズできます。そればかりか単純getterやsetterの動作で言い場合は、省略した書き方もできるようになっています。Javaのように単純なgetterやsetterでもたくさん書かなければならないと言うこともありません(Lombokや一部のフレームワークを使えばアノテーションのみで生成とかできますが)。
ですので「常にprivate」という話はJava以外だと通用しません。他言語を触るときに何も考えずにprivateにしてしまうと、Javaの呪縛から抜け出せないかわいそうな人と思われますので、気をつけてください。
投稿2019/09/29 07:05
総合スコア21737
0
車種, 車幅といった基本的な車の情報を隠蔽する理由が分かりません.
後から書き換える必要が無く、
そして隠蔽する理由も無いのであれば、次のように書いてしまうのもアリだと考えます。
Java
1class Car { 2 ... 3 4 public final double 車幅; 5 public final String 車種; 6 7 public Car(..., double 車幅, String 車種) { 8 ... 9 this.車幅 = 車幅; 10 this.車種 = 車種; 11 } 12}
先生が「データ隠蔽を実現して,プログラムの品質を向上させるために, クラス内のフィールドは,原則として非公開(private)にしよう.」と言っていました.
Java初学者なのですが, それが非常に疑問です.
一般論として正しいです。
フィールドは全てprivateにして、適宜アクセサを用意します。
ただ、jackal_さんの言うように本来隠蔽しなくて良いものを隠蔽しているのも事実です。
私見ですが、Javaがプロパティを言語レベルでサポートしたら前段の一般論は崩れると思います。
投稿2019/09/29 06:36
編集2019/09/29 06:51総合スコア35668
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
車種・車幅を取得したい場合はフィールドをpublicにするのでなく、
車種・車幅を取得するためのメソッド(getter/setterと呼ばれます)を準備するのが定石となっています。
これが定石になっている理由として、
・車の車種は読み取り専用で、外部から変更できないようにする(getterのみを準備)
・例えば、車幅を外部から設定したい場合に、setterメソッドに「3m未満はエラーとする」というような妥当性チェックをすることができる
などのメリットがあります。
オブジェクト指向でプログラムを書く場合のお作法に近いものではありますが、
実際、メソッドの量が冗長になってしまうなど、いくつかのデメリットはあります。。
外部へのリンクとなり申し訳ないのですが、
以下のページが詳しいので参考になさってはいかがでしょうか。
https://qiita.com/katolisa/items/6cfd1a2a87058678d646
投稿2019/09/29 06:01
総合スコア330
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
まず、サンプルがおかしいです。
別にCarクラスを作っても構いませんが、
質問者さん(が感じた)ように意味が理解できない場合が多いです。
OOP等を参考にしてみてください。
これらを参考にして考えると、「オブジェクトだけがデータ(とその変化)および処理を知っている」という状態にできます。
できる限りオブジェクトだけが知っている状態にするため、よほどのことがなければフィールドはprivateにします。
ただし、定数( Javaでは常にどこかのクラスに属していなければならないっていうアレで ) 等のような場合はやむを得ないですが、基本的にはprivate.
[追記0]
ちなみに、すべてpublicにしてしまうとC言語での「グローバル変数」と何ら変わりはありません。
(アクセスするときの書き方が違うだけ)
C言語ですら、グローバル変数は非推奨です。
「グローバル変数 危険性」とかでggってみてください。
投稿2019/09/29 05:51
編集2019/09/29 07:07総合スコア4962
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。