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

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

≪第5回第7回≫

ヒントなんて中途半端なこと言わずに答えそのものを聞けばよかったお。。。
  ::::::::  ::    ::     :::::  ::  :::
  ::::::  ::   ____   :::::  ::::  :::
  ::::::  :::: /  :::  \ :::   :::   ::
  ::::  ::::/   ::     \::  :::  ::
 ::::  /:::    ─    ─ \ ::  ::
 :::  |  ::   .(○)  (○)  | :  ::::
  :::   \     (__人__)  ,/ :  :::
  ::  ノ      ` ⌒´   \ :   :::
  /´               ヽ  :::
 |    l              \:::
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))
     いっそのこと、こんな会社潰してしまえばいいお。
         ___
       /::::::::::::::::\
      /:::::─三三─\
    /:::::::::(○)三(○).\
/⌒)⌒)⌒.:::::::::: (__人__) :::::: \   /⌒)⌒)⌒)
| / / /..    ` ⌒´    | (⌒)/ / / /,,-''ヽ、
| :::::::::::(⌒)          /  ゝ ::::::.,,-''"    \
|     ノ           \  /_,-'"        \
ヽ    /             ヽ /\           \
 |    |        __   //\\           \
             /|[]::::::|_ / \/\\         /
           ./| ̄ ̄ ̄ ̄ //\ \/  \      //    ___
         |  |:::「「「「「「 / \/\  /\\   /:::/   ./| 
       _..|  |:::LLLLL//\ \/  \/\\/::::::/  /  | ロ  .|l
      / llllll|  |:::「「「「 / \/\  /\ .\/ ./::::::::/  / ./ .
__     llllll|  |:::LLL.//\ \/  \/\  /::::::::/   | /  .| ロ
          |  |:::「./ .\/\  /\ \/ /::::::::/⌒ヽ、| ||/ ..|
          |  |:::l//\ \/  \/\_, -― 、  ''"⌒ヽ,_
                (⌒ヽ、_,ノ⌒Y"    Y     .....⌒)
            (⌒ヽー゙ ....::(   ..::.......  .__人.....::::::::
    /_ノ   ヽ_\  でも今まで働いた分がもったいないから
   /( ●) ( ●)\ 次のボーナスもらってから潰すことにするお。
 / ::::::⌒(__人__)⌒:::::\
 |        ̄      |
 \              /
          とりあえず今日はアーキテクトに言われたとおり
          java.ioをみてみるお
           ____
        /⌒  ⌒\
.      /( ●)  (●)\ 
     / ::::::⌒(__人__)⌒::::: \ 
    |      |r┬-|     |  
     \       `ー'´     /
    ノ            \
  /´               ヽ                 カ
 |    l   l||l 从人 l||l      l||l 从人 l||l   カ    タ
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.     タ
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))
     ┌┬┬┐┌┬┬┬┐┌┬┬┬┐┌┬┬┬┐
  ,. - ''"| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ρ ̄`l
   ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ノ ̄
やる夫が見つけてきたのはjavaのファイル出力の基本的なソースでした。
Writer bw = new BufferedWriter(
の部分を
BufferedWriter bw = new BufferedWriter(
と書いていないだけ、少しは何かをつかんでいるのかもしれません。
import java.io.*;
public class HelloWorldFileWriter {
public static void main( String[] args ) {
try {
Writer bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream( "yaruo.txt" ) ) );
String msg = "やる夫で学ぶデザインパターン";
bw.write( msg );
bw.close();
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
<やる夫>
バッファードライターが使いやすいから使いたいだけなのに、
インスタンスの生成までに世話が焼けるクラスだお。。。
         ____
       /      \
      /  ─    ─\
    /    (●)  (●) \
    |       (__人__)    | ________
     \      ` ⌒´   ,/ .| |          |
    ノ           \ | |          |
  /´                 | |          |
 |    l                | |          |
 ヽ    -一ー_~、⌒)^),-、   | |_________|
  ヽ ____,ノγ⌒ヽ)ニニ- ̄   | |  |
<アーキテクト>
お前の書いたソースをみると、
Writer bw = new BufferedWriter( new FileWriter( "yaruo.txt" ) );
でもいいわけだが、まぁいい例を持ってきたな。
お前のやってるその行為はまさに「拡張」と言えるんじゃないのか?
javadocにも、「FileWriter や OutputStreamWriter のような Writer から直接 write() オペレーションを呼び出すのは効率が悪いので、BufferedWriter でラップすることをお勧めします」とあるだろう
        / ̄ ̄\
      /       \ 
      |::::::        | 
     . |:::::::::::     | 
       |::::::::::::::    |          ....,:::´, .
     .  |::::::::::::::    }          ....:::,,  ..
     .  ヽ::::::::::::::    }         ,):::::::ノ .
        ヽ::::::::::  ノ        (:::::ソ: .
        /:::::::::::: く         ,ふ´..
-―――――|:::::::::::::::: \ -―,――ノ::ノ――
         |:::::::::::::::|ヽ、二⌒)━~~'´
             ____
           /      \
          / ─    ─ \    いや、まったく
        /   (●)  (●)  \ そんなつもりはないですお
        |      (__人__)     |
         \     ` ⌒´    ,/
 r、     r、/          ヘ
 ヽヾ 三 |:l1             ヽ
  \>ヽ/ |` }            | |
   ヘ lノ `'ソ             | |
    /´  /             |. |
    \. ィ                |  |
        |                |  |
   / ̄ ̄\  ( ;;;;(
 / _ノ  ヽ\ ) ;;;;)
 |  ( ○) (○)/;;/  
. |   (__人__) l;;,   
  |    ∩ ノ)━・'/  
.  |   /  ノ´ } そこは肯定しとかないとはなしがすすまんだろ
.  ヽ  / /    }   常識的に考えて・・・
   ヽ/ /   ノ
それでは、上記を踏まえて話をニコニコクロニクルの武器クラスに戻して考えて見ます。まず、
// 勇者はこん棒を手に入れた!
Weapon wpInst = new Club();
で装備する武器を表現します。さらに強化アイテムを手に入れてみます。
// 勇者はこん棒を手に入れた!
Weapon wpInst = new Club();
// 勇者は指輪を手に入れた!こん棒が強化された!
wpInst = new Ring( wpInst );
ほかのアイテムでさらに強化してみます。
// 勇者はこん棒を手に入れた!
Weapon wpInst = new Club();
// 勇者は指輪を手に入れた!こん棒が強化された!
wpInst = new Ring( wpInst );
// 勇者は腕輪を手に入れた!こん棒が強化された!
wpInst = new Bracelet( wpInst );
両腕に腕輪をはめることだってできます。
// 勇者はこん棒を手に入れた!
Weapon wpInst = new Club();
// 勇者は指輪を手に入れた!こん棒が強化された!
wpInst = new Ring( wpInst );
// 勇者は腕輪を手に入れた!こん棒が強化された!
wpInst = new Bracelet( wpInst );
// 勇者は腕輪を手に入れた!こん棒が強化された!
wpInst = new Bracelet( wpInst );
// 勇者のアイテム こん棒  指輪  腕輪  腕輪 攻撃力 18
System.out.println( "勇者のアイテム" + wpInst.getDescription() + "攻撃力" + wpInst.getPower() );
/*
// 勇者はこん棒に指輪に腕輪を2つ手に入れた!こん棒が強化された!
Weapon wpInst = new Bracelet( new Bracelet( new Ring( new Club() ) ) );
*/
decoratorDsgnPtn.PNG
見ると、武器クラスを強化アイテムでラップしていることがわかります。図にすると右記のようになるのですが、まず、外側のBraceletからgetPower()を呼んで、ネストしたBraceletに処理を委譲しgetPower()を呼びます。こん棒までたどり着いて最終的に返ってきたgetPowerは(加算されるものとして)武器が強化されたということを表現できるわけです。

このようなクラスの装飾をデコレータパターンと言います。

  • デコレータは、装飾するインスタンス(ここでは武器クラスですね)と同じスーパータイプ(Weapon)を持ちます。
  • 複数の(同じデコレータクラスでも)デコレータを使用してインスタンスをラップすることができます。(アーキテクトの心配はなくなりました)
  • デコレータは装飾するインスタンスに処理を委譲する前後どちらか、または前後両方で独自の振舞いを追加して委譲することができます。

Decoratorパターンの定義はまたまた腹に落ちてこない文言なのですが、

Decoratorパターンはオブジェクトに付加的な振舞いを動的に与えます。デコレータはサブクラス化の代替となる、柔軟な機能拡張手段を提供します。(硬直した継承の爆発ではない方法で、柔軟な機能拡張ができます)
<アーキテクト>
          そういうことだから
          武器クラスをデザインしなおしてみろ
                 __
                /   \
              /ノ   ヽ_\
             | (●) (●)| 
              |  (__人__)  .|  
              l  ` ⌒´  | 
              {         |   
               {       /   
          ,-、   ヽ     ノ、  
         / ノ/ ̄/ ` ー ─ '/ ヽ,
        /  L_         _( { r-、 ヽ
           _,,二)     〔― ‐}     |
           >_,フ      }二 コ\   Li
<やる夫>
          ____         _ _ _ _ _ _ _ _ _ _ _
       /_ノ  ヽ、_\      ( 説明されてもよくわかんないから
.     / (● ) (● )\   ( あまえて誤魔化してみるお。。。
    ///////(__人__)///\   ◯  
    |              | 。O  ̄  ̄  ̄  ̄  ̄  ̄  ̄  ̄  ̄  ̄
     \           /
    ノ            \
  /´               ヽ
 |    l              \
 ヽ    -一''''''
          またまたー。あと500回は同じ説明を
          してもらわないと理解できるような内容じゃないお!
   / ̄ ̄\           ___
 /   /  \        /⌒  ⌒\
 |    ( ○)(○)  プニ   (● )  (● ) \ 
. |     (__人_(ニ~`ヽ、 /:::⌒(__人__)⌒::::: \ 
  |     ` ⌒´(((_⊂>ヽ|     |r┬-|      |
.  |         }    \ \   `ー'´      /
.  ヽ        }      ゝ-|          ヽ
   ヽ     ノ        \        ヽ   \
     ____
    / ⌒  ⌒  \  チラッ
  ./( ―) ( ●)  \ 
  /::⌒(_人_)⌒:::::  | これは政治なのだお。。。
  |    ー       .| フヒヒ
  \          /
        / ̄ ̄\   (こいつに付き合ってると
      /       \  俺の心が先に折れてしまいそうだ)
      |::::::        | 
     . |:::::::::::     | 
       |::::::::::::::    |          ....,:::´, .
     .  |::::::::::::::    }          ....:::,,  ..
     .  ヽ::::::::::::::    }         ,):::::::ノ .
        ヽ::::::::::  ノ        (:::::ソ: .
        /:::::::::::: く         ,ふ´..
-―――――|:::::::::::::::: \ -―,――ノ::ノ――
         |:::::::::::::::|ヽ、二⌒)━~~'´

というわけで、デコレータパターンのサンプルソースを以下に記しておきたいと思います。

import java.io.*;
public class HelloWorldFileWriter {
public static void main( String[] args ) {
// 勇者はこん棒を手に入れた!
Weapon wpInst = new Club();
// 勇者は指輪を手に入れた!こん棒が強化された!
wpInst = new Ring( wpInst );
// 勇者は腕輪を手に入れた!こん棒が強化された!
wpInst = new Bracelet( wpInst );
// 勇者は腕輪を手に入れた!こん棒が強化された!
wpInst = new Bracelet( wpInst );
// 勇者のアイテム こん棒  指輪  腕輪  腕輪 攻撃力 18
System.out.println( "勇者のアイテム" + wpInst.getDescription() + " 攻撃力 " + wpInst.getPower() );
}
}
abstract class Weapon {
String description = "";
public String getDescription(){
return description;
}
public abstract int getPower();
}
// デコレータ抽象クラス
abstract class YaruoDecorator extends Weapon {
public abstract String getDescription();
}
// 具象コンポーネント(装飾される側)
class Club extends Weapon {
public Club(){
description = " こん棒 ";
}
public int getPower(){
return 10;
}
}
// デコレータクラス指輪
class Ring extends YaruoDecorator {
Weapon mWeaponInst;
public Ring( Weapon inst ){
this.mWeaponInst = inst;
}
public String getDescription(){
return mWeaponInst.getDescription() + " 指輪 ";
}
public int getPower(){
return 2 + mWeaponInst.getPower();
}
}
// デコレータクラス腕輪
class Bracelet extends YaruoDecorator {
Weapon mWeaponInst;
public Bracelet( Weapon inst ){
this.mWeaponInst = inst;
}
public String getDescription(){
return mWeaponInst.getDescription() + " 腕輪 ";
}
public int getPower(){
return 3 + mWeaponInst.getPower();
}
}

≪第5回第7回≫

コメントをどうぞ