Swing


天行健 君子以自强不息

posts - 69, comments - 215, trackbacks - 0, articles - 16
   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

设计模式:结构模式之Decorator(油漆工)

Posted on 2007-06-04 15:09 zht 阅读(341) 评论(0)  编辑  收藏 所属分类: 设计模式

Decorator定义:
动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活.

为什么使用Decorator?
我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的.

使用Decorator的理由是:这些功能需要由用户动态决定加入的方式和时机.Decorator提供了"即插即用"的方法,在运行期间决定何时增加何种功能.

程序举例:
Display.java:
public abstract class Display {
 public abstract int getColumns(); // 取得横向的字数

 public abstract int getRows(); // 取得直向的行数

 public abstract String getRowText(int row); // 取得第row个字串

 public final void show() { // 打印所有內容
  for (int i = 0; i < getRows(); i++) {
   System.out.println(getRowText(i));
  }
 }
}
Border .java:
public abstract class Border extends Display {
    protected Display display;          // 指装饰外框里面的「內容」??
    protected Border(Display display) { // 在产生对象实例时,以参数指定「內容」
        this.display = display;
    }
}

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

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

UpDownBorder .java:
public class UpDownBorder extends Border {
 private char borderChar; // 装饰字符

 public UpDownBorder(Display display, char ch) { // 以构造子指定Display和装饰字符
  super(display);
  this.borderChar = ch;
 }

 public int getColumns() { // 字数同內容的字数
  return display.getColumns();
 }

 public int getRows() { // 行数要再加上內容上下的装饰字符的行数
  return 1 + display.getRows() + 1;
 }

 public String getRowText(int row) { // 指定该行的內容
  if (row == 0 || row == getRows() - 1) {
   return makeLine(borderChar, 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.java:
public class Main {
    public static void main(String[] args) {
        Display b1 = new StringDisplay("Hello, world.");
        Display b2 = new UpDownBorder(b1, '-');
        Display b3 = new SideBorder(b2, '*');
        b1.show();
        b2.show();
        b3.show();
        Display b4 =
                    new FullBorder(
                        new UpDownBorder(
                            new SideBorder(
                                new UpDownBorder(
                                    new SideBorder(
                                        new StringDisplay("您好。"),
                                        '*'
                                    ),
                                    '='
                                ),
                                '|'
                            ),
                            '/'
                        )
                    );
        b4.show();
    }
}

注意:display继承类中的getRowText方法
这个方法把所有的用法都继集成到一起