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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Q&A

解決済

6回答

2536閲覧

カプセル化、全部privateにすればいいわけではない?

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

1グッド

1クリップ

投稿2022/03/22 04:40

編集2022/03/22 05:44

Python3系の勉強中にオブジェクト指向について調べている時に分からなかった点について質問します。Python3系に依存しない一般論的な解答でも構いません。

疑問
カプセル化で情報を隠蔽すればフィールドが保護されて安全と聞きました[1]が、
クラスを設計するとき、フィールドのアクセス権を何でもかんでも全部privateにしてgetter/setter or getterを付ければいい、というのは誤解ですか?

そう思った理由
[1]の理由から外部からどのような操作がされるか分かったものではないpublicなフィールドを使う必要はないのではないかという理由です。

出典
[1]
https://webpia.jp/encapsulation/
カプセル化とは、オブジェクトやデータをカプセルのように保護するという意味から来ています。
「オブジェクト内のデータ」を包み
「オブジェクト外からの不正アクセス」から守る
https://kanda-it-school-kensyu.com/java-basic-contents/jb_ch03/jb_0303/
フィールド変数にprivateをつけて他からのアクセスを制限し、専用の操作(メソッド)を用意することをカプセル化と呼ぶ。
private修飾子を利用して外部からの、直接アクセスでメンバ変数の変更を防ぐことができる。
専用のアクセサメソッドを利用することで、外部からの間違ったアクセスを未然に防ぐことができる。 https://www.gamecradle.net/document/main/content/doki/session14/index39.html
外部からクラスメンバに直接アクセスさせない=オブジェクトの動作の安全性・安定性を高める。
https://www.ipa.go.jp/security/awareness/vendor/programmingv1/a03_02.html
故意あるいは事故でデータが損なわれないよう,(略)カプセル化機能を大いに活用すべきである。
……

miyabi-sun👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2022/03/22 04:49

もう少し前提や背景を具体的に記載されたほうが良いと思います。
退会済みユーザー

退会済みユーザー

2022/03/22 04:54

Pythonの勉強中です。 オブジェクト指向について調べている時に生じた疑問です。
m.ts10806

2022/03/22 05:10

念の為Python関連のタグもあったほうが良いです(単にオブジェクト指向とした場合、別言語を例にしたアドバイスがつくこともあります)。また、可能なら「と聞いた」の出典、調べた記事とか。 見てる人は赤の他人なので、どういう前提や背景で質問してきてるか知らない状態です。 何かしら調べたのでしたら記載しておくことで、その記事があってるかどうかとか方向性のアドバイスも得られやすくなります。
fana

2022/03/22 05:14

> フィールドのアクセス権を何でもかんでも全部privateにしてgetter/setter or getterを付ければいい という結論(?)はどこからどうやって導出されてきたのでしょう? そこの部分の{経緯,そう考えるに至った過程,etc…}を述べると良いのかも.
guest

回答6

0

ベストアンサー

クラスを設計するとき、フィールドのアクセス権を何でもかんでも全部privateにしてgetter/setter or getterを付ければいい、というのは誤解ですか?

はい。誤解です。が、よくある誤解な気がします。全てのフィールドにgetter/setterを付けるということは、カプセル化に反したことです。
publicにしないのはもちろんですが、そのクラスにとってきちんと設計されて意味を持ったメソッド以外で、フィールドのアクセスが出来るべきではない(フィールドの隠蔽)というのがカプセル化の意味です。

例えば、人のクラスがあり、(民法的な意味で)成年かどうかを判断する必要があるとします。
おそらく生年月日のフィールドがあると思いますが、生年月日の用途を成年かどうかの判断以外では使わない場合、必要なのは「成年かどうか」(または「未成年かどうか」)を真偽値で返すメソッドです。

ここで生年月日にgetterがあると、現在の日時と引き算して20歳以上かどうかを判断するコードを書かれてしまうかもしれませんので、getterを書いてはいけません。この4月から成年は18歳以上に変わりますが、本来「成年か?」のメソッドだけ修正すれば良いところ、getterを使っている全てのコードをチェックする必要が生じます。
(あくまでタイムリーな例として挙げただけなので、「生年月日の訂正の必要が生じたらどうするのだ?」的な話はこの例の外の話)

また、あるフィールドの実装方法(どんなデータで保持するか、言語の用意しているどの型を使うかなど)も、隠蔽するに越したことはないです。

投稿2022/03/22 06:06

otn

総合スコア84557

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

フィールドが保護されて安全

これは,「隠蔽」の結果によって生じる効果のうちの1つでしかない…というか,
確かにフィールドをprivateにすれば外部から勝手に変更できなくなるわけですが,それは単なる結果でしかないというか…

「隠蔽」の目的とは,そんなフィールドが存在するなんてこと自体をそもそも外部に公開しない(外部からは知り得ないってことにする)こと でしょうから,捉え方がちょっと違うんじゃないかなぁ,と.

例えば,何か複数個のデータに関して「データの平均値を返すよ」っていうメソッドを公開しているクラスがあるとして,
そのクラスが平均値っていうフィールドを持っていてそのメソッドは単にその値を返すのか,それともメソッドを呼ばれた際に都度平均値を計算して返すのか,その他なのか… っていう実装の詳細を外部に見せない(隠してやる)ことで, クラスを使う側(このメソッドを呼ぶ側)がそういった具体的な内部実装形態に依存しないようにする …ってのが「隠蔽」の目的なんじゃないかな.

投稿2022/03/22 05:53

編集2022/03/22 05:55
fana

総合スコア11658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2022/03/22 05:56

※注意:私は python のことは微塵も知りません.
fana

2022/03/22 06:02

何ということか. ページリロードを怠ったまま回答してしまった. 30分も前に > カプセル化の目的はフィールドの保護ではありません。フィールドの隠蔽です。 っていう回答が書かれているではないか.
退会済みユーザー

退会済みユーザー

2022/03/22 06:11

いえ、その一文、引っかかってたので説明ありがとうございました。
guest

0

カプセル化で情報を隠蔽すればフィールドが保護されて安全と聞きましたが、
クラスを設計するとき、フィールドのアクセス権を何でもかんでも全部privateにしてgetter/setter or getterを付ければいい、というのは誤解ですか?

カプセル化の目的はフィールドの保護ではありません。フィールドの隠蔽です。

カプセル化されたクラスを用いるとき、フィールドに対する getter/setter の存在すら意識する必要はないのです。その代わりにそのクラスは必要最小限のアクセサメソッドなりマニピュレーションメソッドを提供するのです。

操作不要なフィールドに対する getter/setter を public にする必要はないでしょう。

それと、フィールドの隠蔽のために private にするというのも早計です。基本的には protected にすべきでしょう。

投稿2022/03/22 05:19

arcxor

総合スコア2859

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/03/22 05:34

では、publicやprivateなフィールドを使うような機会はどういう時でしょうか。
arcxor

2022/03/22 05:49 編集

public フィールドを使ってしまう機会というのは、public getter/setter を使うまでもない簡易的な実装をしたい場合や、public static として任意の値を config 代わりに設定できるようにするといった場合が考えられます。 getter/setter を用意するメリットは、メンバ変数名とアクセス手段の名前を分離できることにもあります。例えば内部的にメンバ変数名を `x` から `_x` に変えたいと思った場合でも、setter を用意しておけば呼び出し側の余計な書き換えをする手間が省けるかもしれません。 また、getter/setter を用意すれば、値を参照する際に正規化処理を挟んだり、値を代入する際にバリデーション処理を挟んだりすることもできます。これらが getter/setter を用意するメリットです。 private なフィールドは、一時的に計算結果や値をキャッシュしておく目的で使う便利変数を隠蔽するために使うことが考えられます。これらのフィールドはサブクラスから参照することがない、あるいはサブクラスを作る予定がない場合には適切なアクセス修飾子かと思います。 protected を用いずに private を多用していると、サブクラスを作った際に不都合が生じることがよくあります。
guest

0

カプセル化はフィールドの隠蔽だけが目的ではありません。カプセル化の本質は、とあるクラスに対して簡単に使用できるようにすることを目的としています。

例えば「時計」クラスがあったとしましょう。これは物理世界にある「時計」を表していると思ってください。そして通常、時計には時間を表示する機能があります。また、時間が狂ってしまったときに調整する機能もあります。

これらは人の目に見える機能です。一方、時間を表示するためには時間を計算し、短針・長針を動かす、というような人の目に見えない機能もありますよね。

カプセル化はこうした人の目に触れる必要のない機能を隠蔽することが目的です。逆にもし、これらの機能が人が見える状態であったら。そしてそれを操作できてしまったら。途端に時計を扱うことがむずかしくなってしまいます。(説明書にこれらの説明も全部書いてあったら混乱してしまいますよね。ただの時計なのに数百ページに及ぶ取説、みたいな)

そしてこうした人の目に触れない機能を実現するために使われるのが private フィールドやメソッドなわけです。そこをうまく隠蔽して人の目に見える機能だけを公開、つまり public にするのがカプセル化の本質です。

クラスを利用するという状況と、時計を利用するという状況が同じ状況なわけです。

こうして見ていくと、publicにすべきフィールドというのが見えてきます。例えば、時計であれば時間を知る必要があるので今何時かを取得できるメソッドやフィールドがあるべきでしょう。

もしアラームの機能を搭載している時計であれば、アラームのオン・オフなども必要になると思います。

なので、原則・基本としてはすべて private にしておき、上記のように外に知らせなければならい機能(言い換えると操作可能とさせる機能)のみを公開( public )にする、というのがこの原則の言いたいことだと自分は解釈しています。

投稿2022/03/29 05:19

edo_m18

総合スコア2283

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

すべての問題を「オブジェクト指向プログラミング」で解決すると死ぬほど複雑になるので、
「ここは絶対にバグを出したくないから型で縛ってチェックしたい」みたいな動機がある箇所だけ使用して、
普段はディクショナリという生データで持ってれば事足りますし、
複数のアイテムを一気に計算する時もディクショナリの配列を作ってmapやfilterなどのリスト操作で一気に変換した方が楽ちんです。

さて、オブジェクト指向プログラミング言語で型でガチガチに縛る時に使うのが「インタフェース」です。
Pythonにはインタフェースはないようです。
参考記事: PythonでC#やJavaのinterfaceみたいなものを実現する - Qiita

インタフェースというのは、
クラスから生成されたインスタンスを唯一存在しているボタン1個押すだけで使えるようにする。
イメージとしては「ドラゴンボールに出てくるホイポイカプセル」みたいに使えるよう
そもそも宣言できるメソッド名やフィールド名を縛るのが特徴です。

かと思いきや、JavaScriptのようにインスタンスにプライベート引数等が存在しない運用ですべてをカバーする漢らしい設計の言語も存在します。


クラスを設計するとき、フィールドのアクセス権を何でもかんでも全部privateにしてgetter/setter or getterを付ければいい、というのは誤解ですか?

根本のpublicなフィールド値を敬遠しろというのは、
あちらこちらで動作に影響にあるパラメータを弄り
「どこが原因でバグを引き起こしているかわからない!」というあるあるを防ぐ目的です。

なのでsetterとかお茶を濁しているだけですね。
「privateにしといてsetterとかお前それ意味あんの?」ランキングで上位に来てしまいます。

PCなどの計算機の速度の向上に伴い、最近では富豪的プログラミングが推奨されるようになりました。
インスタンスを毎回作り直して古いのは捨ててしまえよ!って話です。
Publicなフィールド値しか存在しないJavaScriptは実際の運用ではそうせざるを得ず、これを皆が徹底することでバグを抑え込んでいます。

それが出来ないシビアで高速に動作する事が求められるアクションゲーム等では
同じインスタンスを洗浄して使いまわしたりしますが、
パフォーマンスが許与範囲を下回っていて「こいつがボトルネックだから修正せよ」指示がくだされない限りはメモリの使い方周りは一度放置しましょう。

投稿2022/03/22 06:30

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ィールドの保護について、プログラムの開発のしやすさの観点で考えると良いと思います。

フィールドを public にしてしまうと、どこからでもフィールドの価を変更できてしまいます。
あるフィールドが None になってしまうバグがあったとします。
コードが何万行もあって、そのフィールドへのアクセス(変更箇所) が何箇所もあったとしたら、
None への変更箇所を探すのは大変です。
(代入の箇所全てに None の代入をしていないかの条件で breakpoint をつける?)

フィールド自体を private にして、setter メソッドを public や protected で提供することになっていたとします。
その場合は、sette メソッド中に None の代入をしていないかの条件で breakpoint をつけるだけで
None の代入がいつ行われたかを見つけることができる)

しかし、世の中はそうは単純ではないです。
フィールドが list や dict だったとします。
getter で, そのフィールドそのものを返していたとすると、上の方法では None の代入を見つけることはできません。

疑似的なコード

__some_list = [1, 2] # private はフィールド def get_some_val_0: return __some_list def set_some_list(lst): if lst[0] == None: ブレークさせるたり、ログを出したりして、 __some_list[0] への None 代入を見つける __some_list[0] = lst[0] ...

のようにしていたとします。

するとプログラム中で

v = get_some_val()
v[0] = None

とするだけで、setter に仕込んだ仕組みにひっっからずに __some_val[0] に None を代入できてしまいます。
これにどう対処するかは、いろいろ調べてみてください。

投稿2022/03/22 20:55

編集2022/03/24 00:02
katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問