2012年12月4日火曜日

Decorator パターン(デコレータ・パターン)

Decoratorパターンは、構造に関するパターンのひとつです。

既存のクラスに新たに機能を追加するために
Decoratorクラスでラップして機能を追加する構造になります。
ラップ方法は、継承を使わずにプログラムの実行時に機能を追加します。
 (動的にオブジェクトに機能を追加できる構造)

Decoratorパターン クラス図
Decoratorパターン クラス図
Component・・・・拡張される機能を定義してある抽象クラス
ConcreteComponent・・・Conponentクラスの機能を実装した具象クラス。
Decorator・・・・・・・・・・・メンバー変数にComponentを持つ抽象クラス。
              (※operationメソッドで、Componentのoperationを呼ぶ。)
CooncreteDecorator・・・飾りつけをした具象クラス。
--------------------------------------------------
Componentにあたるクラス。

ファイル名:Display.java

public abstract class Display {
    public abstract int getColumns();               // 横の文字数を得る
    public abstract int getRows();                  // 縦の行数を得る
    public abstract String getRowText(int row
);     // row番目の文字列を得る
    public void show() {                            // 全部表示するoperationメソッド
        for (int i = 0; i < getRows(); i++) {
            System.out.println(getRowText(i));
        }
    }
}
--------------------------------------------------
ConcreteComponentにあたるクラス。

ファイル名:StringDisplay.java

public class StringDisplay extends Display {
    private String string;                          // 表示文字列
    public StringDisplay(String string) {           // 引数で表示文字列を指定
        this.string = string;
    }

    // 独自のメソッド
    public int getColumns() {                       // 文字数
        return string.getBytes().length;
    }
    // 既存の機能
    public int getRows() {                          // 行数は1
        return 1;
    }
    public String getRowText(int row) {             // rowが0のときのみ返す
        if (row == 0) {
            return string;
        } else {
            return null;
        }
    }
}
--------------------------------------------------
Decoratorにあたるクラス。

ファイル名:Border.java

public abstract class Border extends Display {
    protected Display display;          // この飾り枠がくるんでいる「中身」を指す
    protected Border(Display display) { // インスタンス生成時に「中身」を引数で指定
        this.display = display;
    }
}
--------------------------------------------------
ConcreteDecoratorにあたるクラス①。

ファイル名:SideBorder.java

public class SideBorder extends Border {
    private char borderChar;                        // 飾りとなる文字
    public SideBorder(Display display, char ch) {   // コンストラクタでDisplayと飾り文字を指定
        super(display);
        this.borderChar = ch;
    }
    public int getColumns() {        // 文字数は中身の両側に飾り文字分を加えたもの
        return 1 + display.getColumns() + 1;
    }
    public int getRows() {               // 行数は中身の行数に同じ
        return display.getRows();
    }
    public String getRowText(int row) {
    // 指定行の内容は、中身の指定行の両側に飾り文字をつけたもの
        return borderChar + display.getRowText(row) + borderChar;
    }
}
--------------------------------------------------
ConcreteDecoratorにあたるクラス②。

ファイル名:FullBorder.java

public class FullBorder extends Border {
    public FullBorder(Display display) {
        super(display);
    }
    public int getColumns() {                   // 文字数は中身の両側に左右の飾り文字分を加えたもの
        return 1 + display.getColumns() + 1;
    }
    public int getRows() {                      // 行数は中身の行数に上下の飾り文字分を加えたもの
        return 1 + display.getRows() + 1;
    }
    public String getRowText(int row) {         // 指定した行の内容
        if (row == 0) {                                                 // 上端の枠
            return "+" + makeLine('-', display.getColumns()) + "+";
        } else if (row == display.getRows() + 1) {                      // 下端の枠
            return "+" + makeLine('-', display.getColumns()) + "+";
        } else {                                                        // それ以外
            return "|" + display.getRowText(row - 1) + "|";
        }
    }
    private String makeLine(char ch, int count) {         // 文字chをcount個連続させた文字列を作る
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < count; i++) {
            buf.append(ch);
        }
        return buf.toString();
    }
}
--------------------------------------------------
Mainクラス。

ファイル名:Main.java

public class Main {
    public static void main(String[] args) {

        // ConcreteComponentクラスのインスタンス
        Display b1 = new StringDisplay("Hello, world.");
        b1.show();
        // ↓普通の結果
        // Hello, world.

        // ConcreteDecoratorクラスのインスタンスでデコレート
        Display b2 = new SideBorder(b1, '#');
        // ↑#でデコレート
        b2.show();
        // ↓デコレートした結果
        // |#Hello, world.#|
      
       // ConcreteDecoratorクラスのインスタンスでデコレート
        Display b3 = new FullBorder(b2);
        b3.show();
       // ↓デコレートした結果
       // +---------------+
       // |#Hello, world.#|
       // +---------------+

   // もっともっと包む
        Display b4 =
                    new SideBorder(
                        new FullBorder(
                            new FullBorder(
                                new SideBorder(
                                    new FullBorder(
                                        new StringDisplay("こんにちは。")
                                    ),
                                    '*'
                                )
                            )
                        ),
                        '/'
                    );
        b4.show();
   // 結果は三重の枠と*と/で飾られた「こんにちは。」が出力される。
    }
}

0 件のコメント:

コメントを投稿









ロリポップ!なら月々105円から

WordPress、MovableTypeなどの簡単インストール、

アクセス解析、ウェブメーラーが標準装備!






プロペシア