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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

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

Q&A

解決済

3回答

644閲覧

オブジェクト指向設計実践ガイドの中身について〜 attr_readerを用いる理由

shun0211

総合スコア4

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

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

0グッド

0クリップ

投稿2020/06/21 01:06

編集2020/06/21 02:05

「オブジェクト指向設計実践ガイド Rubyでわかる進化しつづける柔軟なアプリケーションの育て方」の2章の中身で一点気になった点を質問させてください。

2章では、以下のコードは良くないコードとして紹介されていました。

code1

1class Gear 2 def initialize(chainring, cog) 3 @chainring = chainring 4 @cog = cog 5 end 6end 7 8 def ratio 9 @chainring / @cog.to_f # <-- 破滅への道 10 end 11end

上のコードではなく、次のようにattr_renderを使ってカプセル化すべきだとあります。

code2

1class Gear 2 attr_reader :chainring, :cog 3 def initialize(chainring, cog) 4 @chainring = chainring 5 @cog = cog 6 end 7end 8 9 def ratio 10 chainring / cog.to_f 11 end 12end

このようにする理由として、@cogのインスタンス変数が10箇所で参照されていたとすると、@cogを修正する必要が生じた場合、修正するために何箇所ものコードを変更する必要があるからとあります。
しかしながら、もし変更するとしてもコード①のinitializeメソッドを修正するだけでやりたい動きができるのではないでしょうか。実際やってみましたが、問題なく動きました。

上のような例の場合、直接インスタンス変数を参照しに行く書き方が良くない理由をご教授いただけたらと思います。
何卒、宜しくおねがいします。

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

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

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

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

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

Daregada

2020/06/21 01:29

`attr_render`ではなく`attr_reader`では?
shun0211

2020/06/21 01:50

誤記ですね、修正しました。もし分かれば回答いただけるとうれしいです。。
Daregada

2020/06/21 01:53

タイトルも修正を(タイトル見て、「ん」と思って覗いたので)
guest

回答3

0

オートマの車を想像するとよいかと思います。

車の速度によって歯車のcogが変わる場合はinitialize一箇所を書き換えるだけでは対応できず
@cogを参照する場所で対応が必要になります。

投稿2020/06/21 06:13

asm

総合スコア15149

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

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

0

私もその本を買って勉強中です。
この章で「@cogのインスタンス変数が10箇所で参照されていたとすると、@cogを修正する必要が生じた場合、修正するために何箇所ものコードを変更する必要がある」と言っているのは、
今は引数から得て@cogに入れた値そのものが使われるが、「@cogを元に演算した結果を使わなければならなくなる場合」が来るかもしれない。その時に修正が大変だ、ということを言ってます。
attr_reader :cog とすることで、otnさんのご指摘の問題が出てきますが、
一方 そうしておいて  def ratio(および至るところ)で @cogではなく cog を使っておけば その時点で attr_reader を消して、
def cog @cog * (foo? ? FooAjaster : BarAjaster) end
とすれば修正完了

ということを言ってます

その割にはいつまでも attr_reader が消えないのは、はてな、でありますが。

投稿2020/06/21 05:50

編集2020/06/21 05:52
winterboum

総合スコア23567

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

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

shun0211

2020/06/21 06:04 編集

winterboumさん回答ありがとうございます。 お互いがんばっていきましょう! 本題ですが、「@cogを元に演算した結果を使わなければならなくなる場合」には、下のようにすれば変更する部分が一箇所で済むように思うのですが、こちらはなにか問題があるのでしょうか? def initialize(chainring, cog) @chainring = chainring @cog = cog * (foo? ? FooAjaster : BarAjaster) end
winterboum

2020/06/21 06:05

別のところで、元々の @cog をそのまま使う必要が有る場合に、困ります。
winterboum

2020/06/21 06:11

あと、foo? が初期化時には決まっていないとか変わりうるという場合もこまるな。
shun0211

2020/06/21 06:42

ご回答ありがとうございます! 確かに上のように定義してしまった場合、もう元々の@cogは使えなくなってしまいますね。 一応元々の@cogを使えるようにするために下のように別で定義するということで理解しました。 def cog @cog * (foo? ? FooAjaster : BarAjaster) end
guest

0

ベストアンサー

@cogのインスタンス変数が10箇所で参照されていたとすると、@cogを修正する必要が生じた場合、修正するために何箇所ものコードを変更する必要があるからとあります。

しかしながら、もし変更するとしてもコード①のinitializeメソッドを修正するだけでやりたい動きができるのではないでしょうか。

のあたりが具体的に何を言わんとしているのか分かりませんが、
少なくとも後者のコードは、chainringcogというアクセサメソッドをパブリックに公開してしまっているので、クラス外からも自由に参照でき、カプセル化という観点からは望ましくないです。

クラス内のメソッドで、インスタンス変数を直接アクセスするのか、アクセサメソッド経由でアクセスするのかは、一律に決められる物では無く、ケースバイケースで判断すべき物と思います。
アクセサメソッド経由の場合も、アクセサメソッドをパブリックにするかどうかは慎重な検討が必要です。

投稿2020/06/21 02:20

otn

総合スコア85901

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

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

shun0211

2020/06/21 05:10

回答ありがとうございます! 本では、下のようにあり後者のコードを押しているのですが、otn様が言われているカプセル化と本で言っているカプセル化は違うのでしょうか。 >> 変数はそれらを定義しているクラスからでさえも隠蔽しましょう。隠蔽するにはメソッドで包みます。 >> Rubyにはかんたんにカプセル化用のメソッドを作る方法として、attr_readerが用意されています。
otn

2020/06/21 05:28

↑は、言っていることがおかしいですね。 本来の「カプセル化」は、クラスの中に実装に関する情報を閉じ込めて、クラス外からアクセス出来なくすることです。クラス外からはインターフェース仕様に従ったアクセスのみ認める。 この人は、「@変数名」を直接書かないことをカプセル化と言っているようです。 安易にアクセサメソッドを作って、インスタンス変数の値をクラス外から直接アクセス出来るようにすることはカプセル化に反します。
winterboum

2020/06/21 05:58

「attr_reader を使ったカプセル化」ですが、何で読んだか思い出せませんが、attr_reader自身を言ってはおらず、カプセル化のための準備の様な意味合いで有ったように思います。 同じクラス内なら インスタンス変数でアクセス出来るわけですが、インスタンス変数そのものではなく、演算するとか、他のモデルからの摂りこみなどに修正するなどの変更時に、予め attr_readerしておいて、@cogではなくcogを使っておけば、def cog でカプセル化するのが容易にできる というような趣旨であったと思います
otn

2020/06/21 06:18

回答に書いたのですが、 > クラス内のメソッドで、インスタンス変数を直接アクセスするのか、アクセサメソッド経由でアクセスするのかは、一律に決められる物では無く、ケースバイケースで判断すべき物と思います。アクセサメソッド経由の場合も、アクセサメソッドをパブリックにするかどうかは慎重な検討が必要です。 細かい話をすると、同一クラス内のメソッドにも、インスタンス変数を使った実装その物のメソッドと、それらとやや縁遠いメソッドがあり得ます。 「インスタンス変数とやや縁遠いメソッドにおいては、クラス外のメソッドに準じてインスタンス変数を直接アクセスしないことにしましょう」というのは妥当な考えです。 つまり、ケースバイケースということです。 少なくとも、後者のために「パブリックな」アクセサメソッドを定義するのは間違っています。
winterboum

2020/06/21 06:24

>少なくとも、後者のために「パブリックな」アクセサメソッドを定義するのは間違っています。 ここは同意です。 便利なのでつい使ってしまいますが。。。
shun0211

2020/06/21 06:31

横からすいません。 インスタンス変数と縁遠いメソッドとはどのようなメソッドなのでしょうか?
otn

2020/06/21 06:37

イメージできなければ、そのコメントは忘れてください。 要はケースバイケースで、メソッドごとにやり方を考えるべきと言うことです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問