オブジェクト指向全般、クラス設計についての質問です。
当方、C#の日曜プログラマであり、数年まえから趣味のプログラミングを楽しんでおりました。
これまではあまりOOPに関する深い部分の理解をしないままなんとなくプログラミングをしてきましたが、このほど、そこらへんの理解を深めるべく名著と呼ばれる以下の書籍を買い漁って理解を深めようと模索しておりましたが、どうも、しっくりきません。
リファクタリング プログラミングの体質改善テクニック(マーチンファウラー)
オブジェクト指向でなぜつくるのか(平澤章)
デザインパターンとともに学ぶ オブジェクト指向のこころ(アラン・シャロウェイ)
(これ以外に名前は失念してしまいましたが、UNLの書籍も読みました)
それぞれの書籍を読んで「うん。なるほど。」というある程度の理解はできているつもりですが、如何せん、自分のコードで・・・となると、ちょうど作文の最初の一文が見つから無いときのような、そんな感覚に襲われてしまします。
これまでの自分のプログラミングというのは、「動けば良い」という部分が最優先であり、かつ、それのみにしかこだわって無かったことも原因としてはありそうです。
その中でも、特に戸惑ってしまうのが、「何をクラスにするのか」という最も基本的な部分です。
今習作として、2ch用ブラウザのコードを書いていますが
クラス候補としていくつかのものを、確信の無い状態で挙げてはみますが
ワード及び原則としての「責務」「単一責任の原則」「高凝集度」「疎結合」・・・
(それぞれの用語や原則の意味は、ある程度理解しているつもりですが)
これらの用語の海で溺れてしまっている感覚で、何をクラスとすればよいのか?という部分で
すでにアップアップしているような感じとなってしまいます。
また、個々のオブジェクトの関連において、あるオブジェクトを保持するのはどのオブジェクトである
べきか?また、あるオブジェクトにメッセージパッシングするのはどのオブジェクトであるべきなのか?等など・・・このあたりについても、一向に頭の中の霧が晴れてくれません。
このような、悩みを解消する考え方、方法、その他おすすめの書籍でも構いませんが、ご助言いただけませんでしょうか?
よろしくおねがいします。
No.3ベストアンサー
- 回答日時:
私も質問者さんと同じように、原則だの設計手法だのに振り回されてコードが書けなくなった経験があります。
今でもたまに手が止まってしまいます。>ちょうど作文の最初の一文が見つから無いときのような、そんな感覚に襲われてしまします。
というのは痛いほどよくわかります。
作文で手が止まってしまうのは、そもそも文章を書き慣れていないと、どうすれば相手に自分の考えが伝わるのか、それ以前に自分が何を伝えたいのかもわからない、読んだ相手がどう思うのか想像出来ないからではないでしょうか。「何を求められているのか」という判断基準そのものが無いが故に手の付け方もわからない状態です。
ソフトウェアの設計も似たようなもので、どんな機能が必要で、どんな問題が起こりうるのか、何処が頻繁に変更され、どんなコードなら自分や他人が把握しやすく、保守しやすいか、みたいなのは、最初のうちは見当つかないものです。熟考すれば出てくるものでもありません。
知識をつけると、最初は問題ではないものまで問題に見えてきます。
そうした段階で分析を行っても、書いていてモヤモヤする、何となく気持ち悪い、違和感がある、みたいな理由しかでてきません。しかし、それは本当に取り組むべき問題ではありません。
実作業に支障を来していないコードを、問題に仕立て上げようとしているだけです。
経験豊富なプログラマなら納得出来る理由を説明し、より良い解決策を提示して設計を見直すかもしれません。
しかし、改善すべき明確な理由も方向性も見えていないのなら、手のつけようがありません。
恐らく何処まで経験を積んでもそういう霧は晴れません。そもそも何が必要になるか、何が問題になるのか、みたいな予知を完全に行うことはできないからです。常に不安はつきまといますし、想定外の仕様変更なんていくらでも出てきます。具体的な形になって使い方が解ると、新たな使い道が見える事も少なくありません。そうしてソフトウェアは進化していっています。
拭いきれない違和感との戦いは終わりがないのも問題です。これこれを達成すればひとまずOKという基準を作るのも設計の一環です。
ならば、真っ先に取り組むべき問題は、書いていてイライラする、実作業に支障が出ているところです。
ある機能を呼び出すのに長~いコード何度も書かなければならなかったり、機能を追加するたびにプロジェクト中の修正を必要としたり、一見関係ないコードを修正すると頻繁にバグったり…。
私が今のところこういう状態に陥ったとき、一番巧くやれている方法は、本やネットで得た知識は一旦シャットアウトして、形にする。そして実際に使い続けてみる。また、複数の方法で作ってみて比較する、です。
そうして問題点を洗い出し、再設計を行います。
これを何度も繰り返します。
いわゆるスパイラルモデルというやつですが、「想定される問題」ではなく、プロトタイピングで「顕在化された問題」に対して取り組むのが重要だというのが私の現在の結論です。勘のきかない経験の少ないコードほどそう感じます。逆に何度も組んだことがあるコードは、繰り返し回数が減り、結果的にウォーターフォールになります。
あるオブジェクトを何処が持つべきか、見当がつかなければ、とりあえずグローバルな場所に置いておきます。
C#ならシングルトンとして作ってクラスメソッドで取得させるとか、メインフォームに置いとくとかです。
作り込んでいくうちに、全く関与しないクラス、殆ど全ての機能からアクセスされるオブジェクトなど、関連性はある程度明確になりますし、グローバルにアクセス出来るオブジェクトの問題点もそのうち直面します。
そのとき、再び本を開いてみてください。書いてある意味がまるで違うことに気がつきます。それを何回も何回も繰り返して、ようやく理解したことになるんだと思います。
だらだらとした長文で「結局経験っすよー」みたいな話ばかりで申し訳ありません。
ですが、少しでも切っ掛けが掴めれば幸いです
参考URLは私が以前した、似たような質問のURLです。ご参考までに。
参考URL:http://oshiete.goo.ne.jp/qa/4167313.html
参考になります。
回答者さんの以前にされた質問も読ませていただきましたが
まさに今の自分と同じです。
>OOPは手段であって目的ではありません。
耳が痛いです。
というやりとりは、自分もホントに耳が痛いです(笑)
そしてまた
そうした段階で分析を行っても、書いていてモヤモヤする、何となく気持ち悪い、違和感がある、みたいな理由しかでてきません。しかし、それは本当に取り組むべき問題ではありません。
実作業に支障を来していないコードを、問題に仕立て上げようとしているだけです。
という部分もマコトに仰る通りです。
霧はまだ晴れてはいませんが、霧の中にいる自分をはっきり見ることはできるようになった気がします。
No.2
- 回答日時:
No.1です。
他に回答が付かないようですので、追加で回答してみます。
>>その中でも、特に戸惑ってしまうのが、「何をクラスにするのか」という最も基本的な部分です。
まずは、C#が手本としたC++、そしてC++の前身である C with Classesが生まれた背景には、「複雑で巨大なソフトウエア開発を行う」という目的がありました。
ですので、"Hello, World!”を1行表示するプログラムのように短くてシンプルなプログラムでは、クラスなんてものの出る幕はありません。
そして、2ch用ブラウザのコードは、それよりもコードは大きく、複雑になると思いますが、まずはオブジェクト指向以前の、構造化プログラミングや複合設計の考え方でデータ構造やモジュール構成、どんな処理が必要か?などを洗い出すところから始めたらいいように思います。
それらの考え方・分析手法を行えば、「責務」「単一責任の原則」「高凝集度」「疎結合」等を考慮したモジュール設計(モジュール分割)ができると思います。
それらのモジュール群とデータ構造で関連の深いものをまとめてクラスにすれば、第一段階のクラス設計ができるように思います。
ここから、さらにポリモーフィズムや継承など、オブジェクト志向からの考え方を取り入れて、さらにクラスを洗練すれば、いいのではないかと思います。
なお、継承は多用すると、共通結合的な弱さがプログラムに持ち込まれるので、できれば使わないほうがいいかもしれませんね。
(昔、継承を使いまくったプロジェクトがあり、開発メンバーの皆が苦しみました・・・)
>>個々のオブジェクトの関連において、あるオブジェクトを保持するのはどのオブジェクトであるべきか?
>>また、あるオブジェクトにメッセージパッシングするのはどのオブジェクトであるべきなのか?
オブジェクト指向の書籍では、しばしば「オブジェクトにメッセージパッシング」という表現を使っていますが、C++やC#では、構文としては、関数呼び出しの変形です。
なので、モジュール呼び出しの親子関係やデータ管理責任はどこが持つべきか?と考えれば、「あるオブジェクトを保持するのは、どのオブジェクトであるべきか?」の答えは自然に決まると思います。
そして、これらの構造化/複合設計の知識があって、初めてクラス設計ができるのだと私は思っています。
ちなみに2ch用ブラウザといった通信系のプログラムは、オブジェクト指向でアプローチするのもいいのですが、その前に、状態遷移図、ステートマシンの考え方で設計するほうがロジックがすっきりすると思います。
構造化/複合設計の参考図書としては以下のものをあげておきます。
・ソフトウエアの複合/構造化設計-/マイヤーズ(1976年発行の本で古いのですけど、今でも十分に通用する内容だと思います。)
・ソフトウエアの信頼性-ソフトウエア・エンジニアリング概説/マイヤーズ (発行 1977年)
・ソフトウエア作法/Brian W.Kernighan、P.J.Plauger(1981年)
参考になります。
OOPが決してある日突然誕生した新しい概念ではなく、連綿と続くソフトウェア技術の進化の形であって
必然的に生まれたものである。
というのは、前に挙げた書籍の文言ですが、真にこの意味を理解できてないように思います。
・・・と、十数年前に買ったC言語の、日焼けして黄色くなったテキストをめくりながら感じました。
No.1
- 回答日時:
質問者さんの質問への正面からの回答ではないのですが・・・
>>その中でも、特に戸惑ってしまうのが、「何をクラスにするのか」という最も基本的な部分です。
その疑問は私の読んだC++の本にも書かれていました。私は「ケースバイケースで、問題を分析して、それで決まる」なんて思っていました。
ただ、最近は、その疑問よりも前に、「クラスを作って、あるいはオブジェクト指向で開発効率はアップするのか?」というもっと基本的な疑問がくるべきでは?なんて思っています。
つまりクラスとかオブジェクト指向って、それらの最終目的は、開発工数の削減とバグを無くすことだと思います。
それは、住宅建設に例えるなら、注文主(施主)の希望に合わせた小さな部材で組み上げる注文住宅(ミスが発生しやすい)より、大きな単位の規格パーツの組み合わせで完成するプレハブ住宅のような、短納期で確実な仕上がりになる方向に向かうのと似ているように思います。
「責務」「単一責任の原則」「高凝集度」「疎結合」などの原則があるのはわかりますけど、先ほどの建築の事例で例えれば、「ノミやカンナの上手い使い方」「ノコで直線に合わせて板を切断するコツ十則」なんてものに相当するのかな?なんて思います。
現在の建築現場では、電動ドライバー、電動丸ノコなど、いろんな電動工具類が作業効率を飛躍的にアップさせています。電動工具で作業する人にとっては、そんな昔ながらの道具の使い方原則は「古いよ!それより新しい電動工具の使い方のノウハウを教えてくれ!」っていうことになりそうです。
上記のような考え方は、C#のバージョン3.5や4.0について記載された本を読んだときに、「クラスは単なる入れ物にすぎない」「新しく導入されたラムダ式は、クラスの原則を壊すもの」「動的プログラミング」なんて記述があり、「目から鱗」と感じたからです。
質問者さんは、幸いC++やJavaでなく、C#を選ばれていますから、C# 3.5以降のそんな機能を大いに教授できると思います。
お勧め本は、川俣 晶さんが書かれた「究極のC#プログラミング~新スタイルによる実践的コーディング」「C#実践ダイナミックプログラミング」「C#ショートコードプログラミング」などです。
たしかに、手段が目的になってはいけない・・・と最近感じてます。
おすすめしていただいた書籍についは、機会があったら読んで見たいと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
パワーポイントのVBAでテキスト...
-
VBAのWindowオブジェクトとWork...
-
C#でフォームのオブジェクト名...
-
時間帯判定をする。
-
Vbで通常使用するプリンターを...
-
サーブレットのクラス図について。
-
VBA 同じ名前のオブジェクトを...
-
Object型からDouble型へのキャスト
-
Excelで =EMBED("Acrobat Docu...
-
0byteのallocaやmemset
-
ワードで画像をドロップすると...
-
MapViewOfFile() はカウンタを...
-
オブジェクト名をforループ内で...
-
ビジュアルC++でボタンの有...
-
Rangeオブジェクトを一時的に作...
-
0埋めについて
-
VBは、コピペを繰り返して規...
-
インタフェース Iterator<E>
-
前置と後置
-
StringBuilderのマルチスレッド
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
パワーポイントのVBAでテキスト...
-
Excelで =EMBED("Acrobat Docu...
-
VBA 同じ名前のオブジェクトを...
-
EXCEL VBAにて動的にCheckBOXを...
-
VBAのWindowオブジェクトとWork...
-
C#でフォームのオブジェクト名...
-
ワイルドカード<?>と型パラメー...
-
COMコンポーネントって何?
-
ビジュアルC++でボタンの有...
-
Object型からDouble型へのキャスト
-
error C2712: オブジェクト ア...
-
newは明示的にした方が良いのか?
-
オブジェクトレベルとメタレベル
-
0 == False はいいけど
-
ASP.net 教えてください!!(...
-
LISTBOXの内容が更新されま...
-
戻り値がクラスオブジェクト
-
時間帯判定をする。
-
Vbで通常使用するプリンターを...
-
ワードで画像をドロップすると...
おすすめ情報