LoginSignup
0
0

More than 3 years have passed since last update.

Decoratorパターン

Posted at

Derocatorパターンとは

オブジェクトに飾り付けをほどこしていく。

Componentの役

機能を追加するときの核になる役。

package decorator;

public abstract class Display {
    public abstract int getColumns();
    public abstract int getRows();
    public abstract String getRowText(int row);
    public final void show() {
        for (int i = 0; i < getRows(); i++) {
            System.out.println(getRowText(i));
        }
    }
}

ConcreteComponentの役

Component役のインターフェースを実装する役。

package decorator;

/**
 * 1行の文字列を表示するクラス
 */
public class StringDisplay extends Display{
    private String string;

    public StringDisplay(String string) {
        this.string = string;
    }

    @Override
    public int getColumns() {
        return string.getBytes().length;
    }

    @Override
    public int getRows() {
        return 1;
    }

    @Override
    public String getRowText(int row) {
        return row == 0 ? string : null;
    }
}

Decorator(装飾者)の役

Component役と同じインターフェースを持つ。
また、Decorator役が飾る対象となるComponent役を持つ。
この役は自分が飾る対象を知っている。

package decorator;

/**
 * 飾り枠を表すクラス
 */
public abstract class Border extends Display {
    // この飾り枠がくるんでいる「中身」をさす
    protected Display display;
    protected Border(Display display) {
        this.display = display;
    }
}

ConcreteDecorator(具体的な装飾者)の役

具体的なDecoratorの役。

package decorator;

/**
 * 文字列の左右に決まった文字で飾りをつけるクラス
 *
 */
public class SideBorder extends Border {
    private char borderChar;

    protected SideBorder(Display display, char ch) {
        super(display);
        this.borderChar = ch;
    }

    @Override
    public int getColumns() {
        // 文字数は両側に飾り文字分を加えたもの
        return 1 + display.getColumns() + 1;
    }

    @Override
    public int getRows() {
        return display.getRows();
    }

    @Override
    public String getRowText(int row) {
        return borderChar + display.getRowText(row) + borderChar;
    }
}
package decorator;

/**
 * 上下左右に飾りをつけるクラス
 *
 */
public class FullBorder extends Border{

    protected FullBorder(Display display) {
        super(display);
    }

    @Override
    public int getColumns() {
        // 文字数は両側に飾り文字分を加えたもの
        return 1 + display.getColumns() + 1;
    }

    @Override
    public int getRows() {
        // 文字数は上下に飾り文字分を加えたもの
        return 1 + display.getRows() + 1;
    }

    @Override
    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) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < count; i++) {
            buf.append(ch);
        }
        return buf.toString();
    }
}

呼び出し元

package decorator;

public class Main {
    public static void main(String[] args) {
        Display d1 = new StringDisplay("Hello world");
        Display d2 = new SideBorder(d1, '#');
        Display d3 = new FullBorder(d2);
        d1.show();
        d2.show();
        d3.show();
    }
}

実行結果

スクリーンショット 2020-09-09 14.19.22.png

包めば包むほど機能が追加されていく。
その際、包まれる側を変更することなく、機能の追加を行うことができる。

こちらを参考にさせていただきました。
増補改訂版Java言語で学ぶデザインパターン入門

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0