一般的なオブジェクト指向言語全体に言えることに言えることで、言語ごとにこういうのあるとか聞けると良いかなと思ったのでタグは色々つけています
ひとつめですが、 static method にするか、 instance method にするかについです
個人的には instance method は this のプロパティや他の instance method を参照するもののみで、インスタンスが持つデータへのアクセスが不要で引数だけから返り値が決まるもの(シンプルなものだと 2つの引数を足す add など)は static にしたいです
プロパティを参照しないものは static に分かれていたほうが見やすく、知らないクラスを見たときにも、このメソッドはプロパティ参照しないことがわかるのはいいことだと思います
しかし、知人から聞いたところテストを考えるとプロパティの参照がなくても instance method にした方がいいとのことでした
その理由は、 static にするとそのメソッドが呼ばれることが決まってしまうが、instance method であればインスタンスをモックに置き換えることで、テストに都合が良いようにできるというものです
add みたいなシンプルなものは不要ですが、返り値のデータが大きく(複雑な構造のオブジェクト)なりがちでそれを使う側のテストではシンプルなデータのほうが確認し易い場合、単に処理に時間がかかる場合、細かい仕様が決まってなく中身が未完成だけど使う側はテストしておきたいとき、などを考えると一理あるように思えます
しかし、テストは作るアプリケーション単体には必要なものでなく、作る側が楽に確認するためのものであり、テストだけのためにほぼ全てのメソッドを static method から instance method にするようなプログラムを見づらくすることは避けたいです
テストのしやすさをとるか、アプリのプログラム単体を見てわかりやすくなるようにするかどちらかをとるしかないものでしょうか?
みんな仕方なく、static でいいものも instance method にしているのでしょうか
2点目です
こっちはC#固有のものかと思います
上で書いたようなモックにインスタンスを置き換える場合です
AクラスがBクラスのインスタンスをもつときに、BをBを継承したB2クラスに置き換えます
Bクラスで各メソッドが virtual 指定されていなければ、override でなく new になり、Aクラス内のBがB2であろうと、Bクラスとしてメソッドが呼ばれるのでB2クラスでなくBクラスのメソッドが呼び出されます
ほとんどのクラスはどこかのクラス内で保持される思うので、テストを考えるとほぼ全部のメソッドがテスト以外に意味もなく virtual になります
有名らしいMoqというライブラリも virtual つけないといけないそうですし、これについては他に方法はなさそうです
テストのためだけに全部に virtual つけていくのが良い書き方とはとうてい思えないのですが、みんな諦めて書いてるものなのでしょうか
謝辞
思った以上にたくさんの回答いただき驚きました
オブジェクト指向って難しいですね
いつまでもオープンのままにしておくのもどうかと思ったのでこのあたりで終了とします
ベストアンサーはすごく迷ったので、一番高評価が多かった回答にしました
ありがとうございました
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答11件
0
ベストアンサー
「ひとつめ」
テストのためにインスタンスメソッド化するのではないのです。
疎結合にするためにインスタンスメソッド化し、疎結合化した結果としてテストもしやすくなるものなのです。
各クラスがスタティックメソッド群に依存しきってしまっていたら、クラスそれぞれを取り出して部品として扱うことは適わなくなります。それを
- スタティックメソッド群をインスタンスメソッド化し
- そのクラスはそれ用のインターフェースを実装した形にし
- 利用する側のクラスはインターフェースへの参照だけ持ってそれに対してアクセスする
という形にすることでクラスからメソッドへの結合を引きはがせる、という話です。これによりメンテナンス性、分業しやすさ、クラスの性質の把握しやすさが向上します。テストもしやすくなっています。
「ふたつめ」
AがB型の参照を持つのではいけません。BのインターフェースをIBへ抜き出し、B implements IBの形にします。AはIB型への参照を持ってアクセスします。そしてテスト用のモックはIBを実装する形で作るのです。
投稿2017/05/19 15:50
総合スコア5570
0
こんにちは。
経験的に「不必要な依存はしない方がよい」という原則は結構頑張って守った方が信頼性の高いプログラムを開発できると思います。
例えば、なるべくprivateにするとか、グローバルにアクセスできる変数はなるべく減らすなどです。
この原則に則ると、instance変数に依存していないstatic methodを、instance methodに変更して依存させるのは、ナンセンスと思います。
逆にいうと、テストしやすいからprivateにしないでpublicにしましょうと言っているのと同じように聞こえてしまいますね。
一部のメソッドだけを本番コードに影響しないように置き換えるって結構難しいですが、そもそも本番コードの設計レベルに影響するような置き換え方法は「無し」と思います。従来通りの泥臭い方法で置き換えるしかないのではないでしょうか?
【追記】
ちょっと質問の主旨から外れますが、instance methodの方が良いと言っている人も少なくないことにちょっとびっくりして、考えてみました。
オブジェクト指向プログラミングって非常に強力です。一般に手続き型フログラミングより適切である場面が多いです。(直感的には95%くらい? もしかすると99%くらいかも。)
そして、instance methodはオブジェクト指向プログラミングの代表的な仕組みの一つであり、static methodは昔からある手続き型プログラミングの代表格です。
なので、一般的には手続き型よりオブジェクト指向型の方がよいよと言う意味で、instance methodを推奨している人も居るような気がします。
一般論では全くその通りと思います。もしも、static methodが異様に目立つプログラムを見たら、オブジェクト指向を使いこなせないプログラマーが作ったのかな?とか思うかも。
しかし、ご質問のケースはstatic methodの方が設計的に適切な場合の話と感じたので、上記の議論には特に触れませんでした。
オブジェクト指向プログラミングが適切なケースは非常に多いので、結果としてinstance methodを使った方が適切な場面は多いと思います。しかし、手続き型プログラミングが適切な場合が皆無というわけではないのでその時にstatic methodを使った方が良い場面も少しはあります。後者を否定するとなかなか悲惨なプログラムが出来上がります。
投稿2017/05/19 15:43
編集2017/05/24 04:53総合スコア23274
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
C# は詳しくないので、ぼんやりした回答になってしまいますが。
static method にするか、 instance method にするか
一般的に、何らかの状態を管理する目的でクラスは作成されます。
管理している「状態」に関係するメソッドがinstance method で クラス自身の何か、例えば生成の Factory method がほしい場合に static method となるので、悩む事はあまりありません。
悩む場合、そもそもメソッドを定義するクラスが妥当かを考える方が良いでしょう。
知らないクラスを見たときにも、このメソッドはプロパティ参照しないことがわかるのはいいことだと思います
利用する側が、プロパティを参照している / していないを意識する必要がある場合、そのクラスのカプセル化が十分でないことを示しており、クラスの責務や提供する機能が何かを再考するとよいです。
instance method であればインスタンスをモックに置き換えることで、テストに都合が良いようにできるというものです
モックのやり方は色々あり、特定のテスティングライブラリの機能にこだわる必要はありません。
テストで他のクラスとの依存関係をモックに差し替えたいと考えたなら、実際のアプリケーションとしてもその部分を疎結合にしたほうがよいことを示しています。
テスタビリティが上がるようにコードを書いたつもりで、読みにくいコードを書いてしまうことはあります。
しかしそれは単に読みにくいコードを書いてしまっただけで、普通に書き直せばよく、どちらかを諦めるという話ではありません。
投稿2017/05/19 23:48
総合スコア938
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
僕は一応C#でごはん食べてます。
回答1.static メソッドをわざわざ instance メソッドにすることはありません。
あるクラスに対して固有なものであっても、staticメソッドは混在しないようにします。
他の方の回答へのレスでファクトリメソッドを例に挙げていますが、ファクトリメソッドはファクトリクラスに纏めて外部化すべき部分です。
そのようにしていくと、最終的にstaticメソッドとinstanceメソッドの共存は無くなるはずです。
回答2.virtualが必要なMockライブラリを使いません。
Moq以外のライブラリを使えば防げる、という他の回答にあるように、モック生成という目的に手段の実装レベルが追いついていないがために起きた不幸です。
まだまだな部分もあるかもしれませんが、今ならinterfaceさえ用意すれば簡単にモックを作れます。例えばNSubstituteだったりFakeItEasyを調べてみるといいです。
質問がでっかすぎて小さなレスポンスが僕の脳みそだと書けません。
こういうの熱く長文書くと間違ってたら恥ずかしいから嫌だなぁって思いますが…
コードこみこみ100行超過して回答をレスしていいならコメントくれれば追記します。
とりあえず、実装したメソッドのテストカバレッジ100%を目指すとか、〇〇を使うが社内ルールだとどうしようもないんですが、そうじゃない場合、ユニットテストのためにコードを捻じ曲げる前に正しい方法が見つかると思います。
着目してることは正しいと思います。問題はたぶん、クラスの粒度が荒すぎるんです。
投稿2017/05/22 13:26
編集2017/05/23 09:09総合スコア1593
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
プロパティを参照しないものは static に分かれていたほうが見やすく、知らないクラスを見たときにも、このメソッドはプロパティ参照しないことがわかるのはいいことだと思います
そのメソッドは本当にそのクラスメンバとして実装するのが妥当でしょうか?
インスタンス内部の状態に全く依存しないということは、演算子や書式化など、本来のクラスの責務とは少し異なる目的を持ったメソッドである可能性が高いんじゃないでしょうか?
そういったメソッド、例えば XXX クラスのファクトリメソッドであれば XXXFactory クラスに追い出して、本来のクラスの責務とは別物としてテストを書くことが出来ます。
また、C# であれば拡張メソッドとして記述することで、やはりクラス本体から切り離して記述することが出来ます。
投稿2017/05/20 02:56
編集2017/05/20 02:57総合スコア403
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
個人的な指針ですが
1つ目
私の場合、基本的にinstanceクラス設計します。
拡張メソッドを作るときにはstaticクラスとしますが、それ以外はinstanceクラスとして設計します。
オブジェクト指向として考えた場合、
・クラスの継承
・インターフェイスの実装
は機能を交換可能なものとして実装するための設計です。
そう考えたときに、staticクラスでは、交換可能な実装になりません。
今、交換が不要でも、将来交換が必要になるかもしれない場合、
instanceクラスとして設計しておくことがメリットになると思います。
この辺の話はSOLIDオブジェクト指向の原則を意識し始めると自然とそうなると思います。
2つ目
ちょっと回答がずれますが、継承よりinterfaceを利用することを意識しています。
何でもかんでも継承するとおっしゃるようにvirtualを付けた・付けないで問題が発生します。
継承を深くするより、機能を分断しクラスを設計し、それをまた集合・集約として利用する方が、
再利用性が高くなると思っています。
他の方もおっしゃっているようにクラスの粒度が大きい、単一責任の原則(SRP)に沿っていないのだと思います。
もう一つ、テストのためにコードが見にくくなることを諦めていません・諦めてはいけません。
ご参考になれば幸いです。
投稿2017/05/23 05:28
編集2017/05/23 05:32総合スコア14
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
質問が2つあるなら、質問を2つ作成して欲しいです。
他の方があとで検索しやすくなりますし、適切にベストアンサーが着きますし、回答者もちゃんと評価されるので・・・
一つ目の回答です。
すべてをstatic methodで書いてはいけないかという点についてですが、それだったらC#の基本的な文法を否定して、変な書き方になるので、他の言語で書くとよいと思います。F#だったらC#より違和感がないかもしれません。
また、関数型言語の場合でも複雑な操作を行う関数は引数が多くなります。その為、バインドや関数渡しなどを使い引数を少なくしてわかりやすくします。Pythonは暗黙のself(this)を最初の引数としてつかっていることからも分かる通り、staticにしようとしまいと同じだけ引数をつかっているのです。(ノイマン型のCPUをつかっているので基本原理は同じと考えてもよいかもしれません。)
オブジェクトは副作用を持つという点について問題がありますが、その問題はオブジェクトをインスタンス後に状態変更出来なくするオブジェクトにするということでこのようなものをimmutableと呼びます。
immutableに出来なくても、できるだけ状態を持たないようにすることで複雑化を避けることができます。
また、javaでMOJOと呼ばれ、.netではPOCOと呼ばれるオブジェクトがあります。これは、継承とかややこしいオブジェクト設計は避けようという動きです。
テストの問題であれば、テストが複雑になる原因がそもそも”プログラムで解決しようとする問題”(以下、問題と呼ぶ)の複雑さにある場合があります。問題が複雑であればテストは複雑になるので、どのように問題を分解するべきかという事では無いでしょうか?
二つ目の回答は、モックを使う場合私は、インターフェイスを使います。現行のオブジェクトをインターフェイスに置き換えるのは面倒ですが、継承を使うとそれはそれでモックオブジェクトの作成が面倒では無いでしょうか。
投稿2017/05/20 01:16
総合スコア2884
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
Pythonはどちらも該当しなさそうです。
ひとつめ
最近のバージョンのPythonであればmockライブラリが標準で入っているので、テストを意識せずに好きに書いたコードでもシンプルに実装されていれば簡単にテストできます。
ふたつめ
Pythonはクラス名.メソッド名
として実行するべきメソッドを明示的に指定できますし、逆にダックタイピングで実行対象を制限せずにself.メソッド名
ともできます。ので、実装時にテストのことを考える必要はこの点でもありません。
投稿2017/05/20 01:13
総合スコア6145
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/05/22 01:39

0
staticメソッドのテストはpower mockなどのフレームワーク使えば良いだけの話ですね。
投稿2017/05/19 15:36
総合スコア854
0
C#でしたら、Fakes FrameworkやPrigを検討してみてはどうでしょうか。
staticだろうがモックできるようになりますよ。
投稿2017/05/23 23:53
総合スコア19
0
C#のモックライブラリーなどは詳しくないため、1つ目の問いにのみとなります。
既出かも知れませんが、テストではなく、オブジェクト指向設計というものが、オブジェクト(モジュール)間の結合強度を下げて、疎結合化するという目的を持った設計技法なので、基本としてインスタンスメソッドを作るようにしています。
(例外はありますが)
疎結合化して、同じ操作でも、オブジェクト毎に異なる振る舞いを行うことを、ポリモーフィズム(多態性)といいますが、これは、オブジェクトを設計する側ではなくて、使う側にとってメリットがあります。
例えば、ウィンドウ制御を行うGUIアプリを作成するような場合を例に挙げると、以下のようなことが出来ます。
Windowというオブジェクトがあるとします。
Windowを閉じる機能として、Closeという要求操作(メソッドなり関数なり、呼び方は言語によってまちまちです)があるとします。
これが、WebブラウザーのWindowなのか、はたまたテキストエディターのWindowなのかに関係なく、ウィンドウ制御側は、CloseというAPIを経由して、閉じたいWindowオブジェクトにウィンドウを閉じるように要求することが出来ます。
これが、所謂インスタンスメソッドといった呼び方をされるものです。
密結合でいいのであれば、ウィンドウ制御側は、Webブラウザーのウィンドウを閉じる操作(=staticメソッド)を呼び出したり、テキストエディターのウィンドウを閉じる操作をしたりしなければなりません。
適当なコードで表現してみると、インスタンスメソッドの場合、
(ちょっとだけC#風にしてみました)
Window window = new WebBrowser();
window.Close(); // ここではWindowのCloseを呼び出している
window = new TextEditor(); // window変数に破壊的再代入していますが、多態性のサンプルとして必要なのでご了承下さい(iPhoneで書くの大変なので)
window2.Close(); // ここではWindowのCloseを呼び出している
と出来ます。
対して、staticメソッドの場合、
WebBrowser.Close();
TextEditor.Close();
としなければなりません。
モック云々で言えば、モックライブラリー次第なので、staticメソッドだろうとモック化出来るので、テストのためではなく、汎用性を高めたり、疎結合化することで、不具合が出たときにモジュール差し替えるだけで修正出来る(Windowsのdllなんかをイメージするといいかも。Javaもクラスファイルの差し替えで同じこと出来ますし)のが、オブジェクト指向設計の基本的な考え方のひとつだったりします。
staticメソッドにも利点はありますが、staticメソッドは構造化設計の考え方とも言われたりする(使い方次第ではありますが)ので、オブジェクト指向言語で設計する際には、基本的には先ずはinterface(言語によってはtraitだったりprotocolといった機能)を用意して、そこに対して実装を行うようにしています。
長いのと、少し古いですが、次のスライドを読むと、疎結合化する意味などが掴みやすくなるのではないかと思います。(相当後のほうのスライドですが)
https://www.slideshare.net/mobile/MoriharuOhzu/ss-14083300
staticメソッドにも利点はあって、所謂Factoryメソッドパターンや、言語的にシングルトンオブジェクトパターンをサポートしていない言語で、シングルトンオブジェクトパターンを実現するような場合には、オブジェクト指向設計でも有用だったりします。
投稿2017/05/23 13:15
総合スコア30
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/05/20 14:39
2017/05/21 00:59
2017/05/21 09:54
2017/05/21 13:08
2017/05/21 13:25
2017/05/23 13:09