ようこそ。睡眠不足なプログラマのチラ裏です。

腐っているクラス(肥大化したクラス)

意味もなく肥大化した大きなクラスを前にしたとき、
多くの健全なプログラマは、ソースコードを眺めただけで吐き気をもよおします。(オエエエエ
つまり、そのクラスを理解できない(理解したくない)状態となり、気分が悪くなるのです。*1

■肥大化したクラスで見られる主な症状
・属性が多く、インスタンス変数が多い
・役割が多岐に渡っていて、処理の意図を読み取りにくい
・他のクラスとの依存度が高い
・全く利用されていないメソッドの存在
・重複したコードが存在する可能性が高い


上記のような症状が見られるクラスがある場合、さまざまな問題を孕んでいるだろう。
これはバグの温床となるだけでなく、保守も拡張も難しくなります。
ただ単に技術的に難しいという意味ではなく、精神的苦痛も伴うという意味でも難しい。
このようなクラスを私は「腐っているクラス」*2と呼びます。
本当に大きくて腐っているクラスの場合、リファクタリングを施すのも大変骨が折れます。


腐っているクラスを蘇生するためには、「クラスの抽出」*3および「サブクラスの抽出」*4が必要となります。

クラスの抽出を考える場合、属性について着目すると、互いに関係深い属性がおのずと見えてきます。
オブジェクト指向に精通していれば、「それらをまとめると1つのモノになりそうだ!」と、すぐにピンときます。
そんなときは、それらを1つのクラスとして抽出するとよいでしょう。
特定のインスタンスでのみ使用される属性がある場合は、サブクラスの抽出をするほうがすっきりすることがある。
どのようにクラスを抽出するとベストなのか、常日頃心がけ「分析力」「観察力」「洞察力」を磨きましょう。



それでは、「クラスの抽出」の例をひとつ。


■抽出前


どうみても、時・分・秒の3つでひとつのモノを表せることは想像に難しくない、常識的に考えて。
そうするとアラーム()操作は、それらと密接に関係していることがおのずとわかる。
この場合、携帯電話クラスから時計クラスとしてクラスを抽出するとよい。



■抽出後


複数のモノが合体したようなクラスの場合、クラスを役割ごとに分解することで、
よりクラスの責任が明確化し、クラスの価値が向上します。
そして当然、利用者(開発者)がそのクラスの意味や役割を理解しやすくなるという利点もある。
クラスを抽出する際には、互いに関係が深く、
同一コンポーネントとして意味のあるものを選択するように意識する必要があるだろう。


上記の例の場合、携帯電話クラスのアラーム()操作は、
お気づきの通り、時計クラスのアラーム()操作に委譲するのが良さそうである。
このように、正しくクラスを抽出するとクラスの役割が明確になります。
「腐っているクラス」は、クラスの抽出ができていない(していない)ものがほとんどです。
「腐っているクラス」は、自身の責任が不明確で、利用者(開発者)も把握しにくい。
「腐っているクラス」は、他クラスの振る舞いに大きく依存し保守・拡張性を失います。


よって、「腐っているクラス」を蘇生するためには、それらを取り除く治療が必要。
まずは役割分担をし、クラスの抽出を行って責任を明確化すること。
そして他クラスとの依存度を極力減らす必要があるでしょう。


腐っているクラスは、あたかも腐ったみかんのように、
他のクラスに悪影響を及ぼし、腐ったクラスを次々と産み出す「悪のクラス」です。
リファクタリングによる悪のクラスの撲滅方法を学ぶことももちろん重要なことですが、
なによりも、常にそのようなクラスを作らないよう、
クラスの意味や役割を吟味した上でのクラス作成を心がけることが大切です、


クラス設計はSEとPGが力を合わせ、
ディスカッションしてやるといいお(`・ω・´)



関連記事
重複したコード 2007-03-19

*1:オブジェクト指向言語なのに、全くオブジェクト指向していないときも吐き気をもよおすことがあります。

*2:肥大化したクラス

*3:クラスの責任を切り離す方法を決め、新たなクラスを抽出し、そのクラスに対して元クラスからリンクを張ること。

*4:あるクラスが特定のインスタンスだけでしか使われない振る舞いを持っていることがわかった場合、その一部の特性を持つサブクラスを作成するとよい。