Java最大の罪は、オブジェクト指向を知らない(自称)オブジェクト指向プログラマを量産したことだと思う [日記]
タイトルにJavaとあるけど、中身はC++。
プロジェクトが順調に進んでいるとプロジェクトマネージャは暇になるのでしょうか?
ある日「今、手が空いているから何か手伝う」と言い出しました。
そこで、
『2つのファイルの内容が等しいか判定する関数を書いて』とお願いしました。
そして出来上がったのが、こんなクラスでした。
class FileComparator { private: const char* path1_; const char* path2_; public: FileComparator(const char* path1, const char* path2) : path1_(path1), path2_(path2) { } bool compare() { FILE* fp1 = fopen(path1_, "r"); FILE* fp2 = fopen(path2_, "r"); int c1, c2; do { c1 = fgetc(fp1); c2 = fgetc(fp2); } while (c1 == c2 && c1 != EOF && c2 != EOF); return c1 == c2; } };
これは、ひどい(某氏風に)
1バイトずつ読むのはパフォーマンス的によろしくない……というわけじゃなくて。
最近のマシンは、ハードディスクドライブがキャッシュを持っているし、OSもディスクキャッシュを持っているから、1バイトずつ読んでも、それほど無駄が多いわけじゃないと思う。(実際にどうなのかは知らない)
エラー処理が無い……というわけでもなくて。
確かに問題だけど、この際それはどうでも良かったり。
一番の問題は、実装以前。
どうして、こんな『クラス』を作っちゃうかな。
「クラス」と言うものが何なのか、まるで理解してませんよね。
こういう人が、デザインレビューと称してクラス図を見ながらツッコミを入れているのだから、オブジェクト指向設計が出来る人材がちっとも育ちません。
閑話休題
そもそもが、関数(動作)を中心に考えるC言語のやり方で、「クラス」を関数の発展系として捉えているから、こうなるのです。
メンバ変数は、実際に引数に指定しなくても使える引数のようなもの(隠れ引数)という扱いです。
どちらかと言えば「クラス」は変数(データ型)の発展系なのですよ。
いい加減にC++とC言語は別の言語だということを理解しましょう。
では、どうしましょう。
駄目なクラスの手っ取り早い判定方法は……、
クラスの説明が「○○するクラス」となったら、アウト。
ちなみに、「○○するクラス」は、"publicなメソッドが1つだけ"という特徴を持ちます。
前述のクラスは、「ファイルの比較をするクラス」で、publicなメソッドが"compare"
の1つだけという、実に典型的な駄目クラスです。
では、これを修正します。
- メソッドの引数(メンバ変数になっている隠れ引数も含む)をクラスにする。
- そのクラスのメソッドとして、元のクラスのメソッドを追加する。
- 後は、良い感じに調整する。
前述「ファイルの比較をするクラス」のメソッド(compare
)に引数はありませんが、メンバ変数が隠れ引数なので、コレをクラスにします。
でもって、色々と修正した結果がコレです。
class File { private: const char* path_; public: File(const char* path); bool equalBody(const File& file) const; };
どうですか?
出来ること自体は元のクラスと変わっていませんが、将来クラスを拡張しようとした時の再利用性は断然向上していると思いませんか。
さて、
当初の予定では、完成形は、こんなのでした。
namespace FileUtil { bool compareFile(const char* path1, const char* path2); }
どうせ、自動テストでちょっと使うだけの使い捨て関数のつもりだったので、
きちんと
『2つのファイルの内容が等しいか判定する“関数”を書いて』
とお願いしたのです。
適当に言っているわけじゃないのですよ。
functorとか関数オブジェクトとか呼ばれているものは「○○するクラス」ですけど、デリゲータやラムダ式をサポートしていない言語のための代用品ですので、functorとして使うためだけに作るべきでしょうね。
前述の「ファイルの比較をするクラス」も、functorにするつもりだったのなら、この様にお書き頂きたかった(某氏風に)
class FileComparetor { public: bool operator()(const char* path1, const char* path2) const; };
今日の一冊 | |
|
コメント 0