例えば「色」クラス(Color
)を作っていたとして、その色を反転させたり、明るくしたり暗くしたりできるものだとします(メソッドで)。
ここでこの Color
をメソッドチェーンを利用できるようにしたい場合、二通りの方法が思いつきました。(ここでは色を反転させるメソッドとして考えます)
- 自分の色を反転させた色を持つ
Color
のインスタンスを返す。(自分は変更されない) - 自分自身の色を反転して自分を返す
これはどちらが良いのでしょうか?
普通はこういう実装をする、とかありますか?
要するに
C#
1var baseColor = new Color(12, 34, 56); 2var anotherColor = baseColor.Invert().Lighten(0.2).Saturate(0.5);
みたいにしたときにbaseColor
が変更されているべきか否か、ということです。
自信を変更したくないときのために、Clone
とかいうメソッド(自分と同じ色をもつインスタンスを生成し返す)を作って対処する方法も浮かびましたが、普通こういった実装をしたりしますでしょうか?
皆様のご意見をお聞かせください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ベストアンサー
その言語の特徴やメソッドチェーンする対象によって傾向があると思います。
自分自身を変化させるような場合はmutableなオブジェクト、自分自身は変化させずにそのままにする場合はimmutableなオブジェクトと言ったりします。この用語に合わせてmutableなメソッドチェーン、immutabelなメソッドチェーンとして説明します。なお、mutabelなオブジェクトには両方あり得ますが、immutableなオブジェクトはimmutableなメソッドしかありません。
###メリットとデメリット
メリットとデメリットをまずは見ていきましょう。
####mutableなメソッドチェーン
利点
- オブジェクトの生成が無いため、速い
- メモリの消費量が少ない
- メモリ管理が不要
欠点
- 副作用があるため、何をしているかを把握しないと危険
####immutableなメソッドチェーン
利点
- レシーバを変更されるといった副作用が無いため、安全
欠点
- オブジェクトを逐一生成するため、遅い
- 途中に作成されたオブジェクトの分だけメモリが消費されていく
- メモリ管理が複雑になるため、GCが無いと難しい
上を見るとわかるように対比になっています。基本的には、「パフォーマンス」を取るか、「安全性」を取るかです。また、GCが無い言語でimmutableなメソッドチェーンを作るには工夫がいります。途中でメモリの動的確保により生成したオブジェクトがある場合、そのままではメモリ解放することができなくなってしまうからです。
###どのような場合に多いのか
上を踏まえて、対象となるオブジェクトや言語によって傾向があります。(言語は偏っていますし、私感です)
####mutableなメソッドチェーン
- IOオブジェクト … 読み込みや書き込みは必ず副作用を伴う物ですので、レシーバは必ず変更されます。そのため、わざわざ新しいIOオブジェクトを作るメリットがありません。C++のstd::iostream、RubyのIO等。
- C++ … GCがないためimmutableで作ること自体が難しいです。また、C++では安全性よりパフォーマンスを重視しており、使用する人もいかに速くできるかに関心があります。遅いimmutableは敬遠される傾向になります。
- 昔のJava … 昔のJavaは全体的に遅いと言うこともあり、速くできるところは速く使用としていた傾向があります。
####immutableなメソッドチェーン
- ストリーム(リスト)オブジェクト … 関数型で見られるような処理ができるパターンです。ストリーム(リスト)を抽出、射影、並び替えなどを次々行います。JavaのStream、C#のLINQ、RubyのEnumerable等。
- 今のJava … 最近のJavaに追加されたクラスはimmutableな場合が多い傾向にあります。パフォーマンスもよくなったため、速度よりも安全を取るという選択です。
- Ruby … Rubyのオブジェクト自体はmutableなものが多いですが、ほとんどの場合で、新たに生成したオブジェクトを返すメソッドが用意されています。それらとは違い、副作用を伴うメソッドは破壊的メソッドとよんでなるべく区別できるようにしています。それら破壊的メソッドはnilを返す事もあるようにして、わざとメソッドチェーンをしにくくしています。自然と破壊的メソッドではないimmutableなメソッドチェーンを使うように洗脳する恐ろしい言語です。
###まとめ
昔はマシンも貧弱であり、パフォーマンスが重視されていたため、mutableな傾向が強かったと思います。しかし、近年は、マシン速度が向上し、関数型プログラミングの流行に伴い、immutableな実装が主流ではないかと思います。速度と安全は二律背反であり、どちらがか正解という物ではありません。用途や目的などに合わせて選ぶと良いかと思います。
投稿2016/07/02 22:25
編集2016/07/02 22:51総合スコア21735
0
個人的には,どっちが正解とかはないように思います.
わかりやすさのために新しいインスタンスを返す場合もあるし,わざわざ別オブジェクトを確保するのが嫌だからそれ自体を変えてしまう場合もある.
ただ,全体として統一されたルールで動くことと,メソッド名との兼ね合いだけは重要だと思っていて,例えば例示されているような場合,オブジェクト自体を変更するときはinvert
で,新しいオブジェクトを返すときはinverted
にするとか,ルールを決めています.
実際ライブラリとかでは,動詞の原形(命令形)と受身形(過去分詞)で両方の動作を提供する実装なんかもありますし.
投稿2016/07/02 15:12
総合スコア442
0
正解は無いと思います、時と場合によるとしか言えないというか。
普通はこうするではなくて、こういう場合はこうするというベストプラクティスはあるのかも知れませんが。
何かの問題に対しての解決方法で、1つあれば完璧ということはまずなくて、
必ずメリット・デメリットがあるわけで、
重要なのは選択肢が沢山あってその時々に応じて最適なものを選べるかです。
ソートアルゴリズムなんてたくさんありますよね。
つまり何かを解決する際にひとつしか選択肢が無いという状態が一番ダメなわけで、
何パターンも考えつく質問者様は、素晴らしい思考の持ち主だなぁと思いました。
まぁ、換装だけ述べても何なので、クラスのデザインというものに関して言えば
古?よりデザインパターンというものが存在しますので、そちらを研究するのも良いのではないでしょうか。
メソッドチェーン デザインパターン で検索すればいろいろなパターンが見つかります。
結果の中には、GoF(ギャング・オブ・フォー)のチェインオブリポジトリーも出てきますので、
それがメソッドチェーンとイコールになるのか不勉強で分かりませんが、参考になると思います。
投稿2016/07/02 15:21
総合スコア2208
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/02 15:26
2016/07/02 17:33 編集
2016/07/03 00:04
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/02 22:34
2016/07/02 22:52
2016/07/04 17:10