裏口からのオブジェクト指向プログラミング

C++オブジェクト指向でプログラムを組むというのは結構大変である。少なくとも私は身に付くまでにわりと苦労したorz 職場でも皆苦戦している。特に手続き型で長く開発をやってきた人はひときわ苦労している。しかし逆に初心者はわりとすんなり出来たりする。ちょっとうらやましい。
なんでなかなか覚えにくいかというと、おそらくその抽象的な概念にあると思う。まずはその思想を理解して、その思想の元に設計をおこない、その設計通りに実装を行う。重要なのは思想であってコーディングではない。プログラムの文法はその思想を実現させるために決められているのであって、それ以外の用途で使うべきではない。プログラムを書くとなるとどうしてもコーディングを中心に考えてしまいがちだがそれだとなかなか理解できない。なので、ぶっちゃけた話、一度プログラムから離れて、要求→仕様→設計の部分のみの訓練をするのがいいのかもしれない。

職場でOOPを教えるようになって漸く2年程経つが、教える立場に立ってみてOOPっぽくない具体的な実装がだんだん分かってきた気がする。ずっと抽象的立場からレビューを行っていたので指摘してもあまり理解されないことが多かった。「そこをそう変えることによってどんなメリットがあるのですか?」といわれて説明できないことも多々あり(ダメじゃん)。そんなダメレビュアーなのだが2年経つとだんだん分かってきた。逆に言えば、OOPっぽくない実装を徹底排除すればOOPの思想をすっ飛ばしてもそれなりな設計になるんじゃないかなと考えてみた。というわけでまずは列挙してみる。

  • グローバルな関数や変数を使わない。
  • メンバ変数はすべてprivate。
  • staticな変数・関数を使わない。
  • オーバーライドのない継承を行わない。
  • 10行以上同じになる部分を作らない。
  • 一つのメンバ変数に対するゲッタメソッドとセッタメソッドはどちらかのみ。
  • メンバ変数のポインタや参照は出さない。出す場合はconstに。
  • 1ファイルにつき1000行まで。メソッドは200行まで。
  • クラスとpublicメソッドは必ず簡潔なコメントを入れる。
  • 構造体を使わない。

かなり乱暴だが一度上記の規約でプログラムを組んでみるというのはかなりの訓練になるかもしれない。少なくとも私の書くプログラムは上記を守っている。いや、OOPで組んでいると結果として上記を満たすようになるはずである。もちろん例外もあるから頑なに守る必要は全然ないのだが、最初は徹底してみるのもよいかも。

以下、理由を簡単に説明。

グローバルな関数や変数を使わない
まあ常識ですね(^^; あえて説明は省きます。
メンバ変数はすべてprivate
オブジェクトを抽象的に扱うにおいてメンバ変数は具体的すぎる。こいつを隠蔽しないことには前に進めない。
一つのメンバ変数に対するゲッタメソッドとセッタメソッドはどちらか片方のみ
両方入れちゃったら結局publicに置いているのと一緒。せめてどちらかに工夫を入れるとか(何)
メンバ変数のポインタや参照は出さない。どうしても出す場合はconstに。
外から操作できちゃったらpublicにおいているのと一緒
構造体を使わない
上記3つを封じるのだから必然的に使うことは禁止になる。
staticな変数・関数を使わない。
これはOOPでも使うことは多いが、使い方を誤る典型的な文法なのであえて禁止に。実際、無くても十分OOPで作れるし。
オーバーライドのない継承を行わない。
これもOOPであっても使うことはあるが、使い方を誤る典型的な文法なので禁止にすべき。インターフェースの概念をまずは覚えないと。
10行以上同じになる部分を作らない。
OOPに限ったことではないが同様の処理を1箇所に集めるのは品質向上への必須事項である(何様)
1ファイルにつき1000行まで。メソッドは200行まで。
やたらでかいクラスは大抵どこか設計を誤っている。大抵は分離できたり、やたらコピペが多かったりする。
クラスとpublicメソッドは必ず簡潔なコメントを入れる。
設計がおかしいと簡潔に説明できないことが多い。:周りのクラスを巻き込まないと説明できないなら設計を怪しんでいいと思う。


まああくまで私の実験的な考えであって上手く行くかどうかは分からないけど。