やる夫がデザインパターンをやるようです 第2回

やる夫がデザインパターンをやるようです 第2回をはてなブックマークに追加 やる夫がデザインパターンをやるようです 第2回をdel.icio.usに追加 Yahoo!ブックマークに登録 やる夫がデザインパターンをやるようです 第2回をGoogle Bookmarksに追加

≪第1回
第3回≫

やる夫は先日の失敗から継承について考えてみました。
Heroクラスを継承するヒーローたち全てが飛ぶわけではなかったのです。ということは、飛ばしてはいけない実装を個々のサブクラスにしてあげればよいわけです。

<やる夫>
     ____
   /      \ そういえばボケモントレーナーを実装したときに
  /  ─    ─\ punch()メソッドやkick()メソッドを
/    (●)  (●) \ オーバーライドしたな。。。
|       (__人__)    |
/     ∩ノ ⊃  /
(  \ / _ノ |  |
.\ “  /__|  |
  \ /___ /
class Hero {
punch()
kick()
jump()
display()
fly()
}
class ボケモントレーナー extends Hero {
punch(){
// ボケモントレーナー自身はパンチ出来ない。
// 保持しているボケモンにパンチの指示を出す。
}
kick(){
// ボケモントレーナー自身はキック出来ない。
// 保持しているボケモンにキックの指示を出す。
}
display(){
// ボケモントレーナー
}
}
<やる夫>
       ____
     /⌒  ⌒\ だったら、飛ばないヒーローは、fly()メソッドを
   /( ●)  (●)\ 空実装してやればいいお
  /::::::⌒(__人__)⌒::::: \
  |     |r┬-|     |
  \      `ー'´     /
やる夫は、Heroを継承するクラスにおいて、飛ばないヒーローはfly()メソッドをオーバーライドして何もしないようにすることを思いつきました。
class サザエさん extends Hero {
display(){
// サザエさんの表示
}
fly(){
// サザエさんは飛ばない。なにもしない。
}
}
<やる夫>
       ____
     /⌒  ⌒\ これで飛ばないヒーローたちを実現できるおww
   /( >)  (<)\ どう考えても天才の発想だおwww
  /::::::⌒(__人__)⌒::::: \
  |    /| | | | |     |
  \  (、`ー―'´,    /
       ̄ ̄ ̄
<アーキテクト>
お前はウチのきゅんぽな企画のこと知ってて言ってんのか?
ヒーローたちはリリースしても数ヶ月ごとにバージョンアップする。
ヒーローが追加される可能性だってあるわけだ。
てめぇはその度にfly()メソッドなんかを調べて
オーバーライドしていくのか?
        / ̄ ̄\
      /       \
      |::::::        |
     . |:::::::::::     |
       |::::::::::::::    |
     .  |::::::::::::::    }          ....:::,,  ..
     .  ヽ::::::::::::::    }         ,):::::::ノ .
        ヽ::::::::::  ノ        (:::::ソ: .
        /:::::::::::: く         ,ふ´..
-―――――|:::::::::::::::: \ -―,――ノ::ノ――
         |:::::::::::::::|ヽ、二⌒)━~~'´
<やる夫>
       ____
     /⌒  ⌒\ ホジホジ
   /( ●)  (●)\
  /::::::⌒(__人__)⌒::::: \  ?
  |    mj |ー'´      |
  \  〈__ノ       /
    ノ  ノ
やる夫はよくわかってないようですが、Heroクラスを継承している以上、そのサブクラスはfly()メソッドや、punch()メソッド、kick()メソッドに依存し続けなければなりません。
ということは、サブクラスが増える度にこれら全てのメソッドをチェックして、空実装でオーバーライドするか、固有の処理としてオーバーライドするか、あるいは、スーパークラスの処理をそのまま使うかなどを調査し、実装していくことになります。
いまのやる夫には、「ヒーローの型の一部だけがパンチしたり飛んだりキックしたりする」というわかりやすい方法が必要なのです。
<やる夫>
じゃあPunchableとかKickable、Flyableインターフェイスを
作ってこいつを必要なヒーローにインプリメントすりゃいいお。
       ____
     /⌒  ー、\ 
   /( ●)  (●)\
  /::::::⌒(__人__)⌒:::::\ 
  |     |r┬-/ '    |
  \      `ー'´     /
<アーキテクト>
   / ̄ ̄\
 /   _ノ  \
 |   ( ●)(●)  てめぇはもう喋るんじゃねー
. |     (__人__)____
  |     ` ⌒/ ─' 'ー\
.  |       /( ○)  (○)\
.  ヽ     /  ⌒(n_人__)⌒ \  
   ヽ   |、    (  ヨ    |
   /    `ー─-  厂   /
   |   、 _   __,,/     \
やる夫が発案した方法はJavaで言うinterfaceのimplementsです。
スーパークラスからパンチ、キック、フライメソッドを取り除き、interfaceとして定義します。それを必要なヒーローに実装してあげる方法ですが、例えばパンチという振る舞いにほんのちょっとした変更が共通的に加わった場合に、パンチを実装しているクラス全てに変更をして回る必要があります。いわゆる重複コードです。ではどうすればよいのでしょうか。。。

この「やる夫がデザインパターンをやるようです 第2回」では、ソフトウェア開発において考える必要のある大事なこと、「変更」について述べてみました。そもそもアプリケーションは「変更」され続け、成長・変化していくものです。そうでないとユーザは使ってくれません。ですが、その変更部分をソースにばら撒くようなことはしたくありません。今のやる夫はそれを知る必要があります。

というわけで、第2回はここで終わります。

≪第1回
第3回≫

コメントをどうぞ