「グラフィックデザインパターンは、」この研究は、5-2 Decoratorパターンをノート

デコレータパターンDecoratorパターンすなわち、クラスは、下記のコードによって装飾されます。

コードを示してい

コードは、の内容を示して

ハローワールドのような言葉を表現:クラスStringDisplayがあります。

私たちは、この文のデコレータによって装飾 - フォームの周囲に境界線を追加| Hello Worldの|に加え、上部と下部の境界線は、これらの言葉に囲まれて、フォーム

+-------------+
|Hello, world.|
+-------------+

UMLダイアグラム

各クラスの解釈

表示カテゴリ:代表一段话的显示使用した模版方法モデルを、等列、行の数を得るために、抽象メソッドを定義し、それは、これらの方法の使用を指定します。

StringDisplayカテゴリ:代表一句话的显示継承と表示中のすべての抽象メソッドを実装します。

Borderクラス:代表对一句话的装饰継承とディスプレイのカテゴリを委託。それは抽象的な装飾です。

SideBorderカテゴリ:代表对某一行的左右添加装饰字符ボーダーは(意味は、表示カテゴリを継承)クラスを継承し、その抽象メソッドを達成しました。

FullBorderカテゴリ:代表对某一行的上下左右添加装饰字符そしてSideBorderクラス、および抽象メソッドは、Borderクラスとディスプレイのカテゴリを継承して実装しています。

コード

public abstract class Display {
    public abstract int getColumns();               // 获取横向字符数
    public abstract int getRows();                  // 获取纵向行数
    public abstract String getRowText(int row);     // 获取第row行的字符串
    public void show() {                            // 全部显示
        for (int i = 0; i < getRows(); i++) {
            System.out.println(getRowText(i));
        }
    }
}

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;
        }
    }
}

public abstract class Border extends Display {
    protected Display display;          // 表示被装饰物
    protected Border(Display display) { // 在生成实例时通过参数指定被装饰物
        this.display = display;
    }
}

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;
    }
}

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) {         // 生成一个重复count次字符ch的字符串 
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < count; i++) {
            buf.append(ch);
        }
        return buf.toString();
    }
}

public class Main {
    public static void main(String[] args) {
        Display b1 = new StringDisplay("Hello, world.");
        Display b2 = new SideBorder(b1, '#');
        Display b3 = new FullBorder(b2);
        b1.show();
        System.out.println();
        b2.show();
        System.out.println();
        b3.show();
        System.out.println();
        Display b4 = 
                    new SideBorder(
                        new FullBorder(
                            new FullBorder(
                                new SideBorder(
                                    new FullBorder(
                                        new StringDisplay("hello world!!!")
                                    ),
                                    '*'
                                )
                            )
                        ),
                        '~'
                    );
        b4.show();
    }
}

/*
结果
Hello, world.

#Hello, world.#

+---------------+
|#Hello, world.#|
+---------------+

~+--------------------+~
~|+------------------+|~
~||*+--------------+*||~
~||*|hello world!!!|*||~
~||*+--------------+*||~
~|+------------------+|~
~+--------------------+~
*/

ロールモデルとクラス図

役割

  • コンポーネント:装飾的な役割は、唯一のAPIを定義します。本実施形態では、ディスプレイのクラスは、この役割を果たしています。
  • ConcreteComponent:コンポーネントAPIを実装し、装飾するための具体的な役割です。本実施例では、クラスがこの役割を果たしてStringDisplay。
  • デコレータ:デコレータ同じコンポーネントのAPIを持つ、装飾品は、コンポーネント内部に保持されています。本実施形態では、Borderクラスは、この役割を果たしています。
  • ConcreteDecorator:特定のデコレータ。SideBorderとFullBorderすることで、この場合には、この役割を果たしています。

クラス図

アイデアを展開

インタフェース(API)透明性

Decorator继承了Component,装饰物和被装饰物具有一致性——他们有着相同的API接口。即便API接口被装饰了一遍,也不会被隐藏起来,其他类依然可以调用被装饰后的API接口。可以用这个特性实现递归装饰。

为什么使用继承和委托

使用继承,是为了获得一致性,如上所说。

为什么使用委托呢?

如果只有继承,由于Decorator继承的是抽象的被装饰类,意味着我们要再实现一遍被装饰者的API,一旦被装饰类的API的逻辑发生改变,被装饰者也要改一次。

那如果Decorator继承的是具体的被装饰类呢?这样可以实现类似于委托那样的实现,直接调用父类的方法就可以了。

这样做的坏处至少有一个:有多少个具体的被装饰类,就要写多少遍装饰类。麻烦死了,而且重复代码一堆,绝不是什么好事情。

所以还是用委托吧。

java.io包和装饰者模式

//读取文件
Reader reader = new FileReader("xxxx.txt");
//读取时将文件放入缓冲区
Reader reader = new BufferReader(
                    new FileReader("xxxx.txt") 
               );
//还要管理行号
Reader reader = new LineNumberReader(
                    new BufferReader(
                        new FileReader("xxxx.txt") 
                    )
               );
...

缺点

增加很多功能类似的很小的修饰类

おすすめ

転載: www.cnblogs.com/qianbixin/p/10992969.html