设计模式 – 装饰模式(Decorator)

问题的提出:一个人装扮,可以先穿裤子,再穿衣服,再穿鞋子;也可以先穿衣服,再是裤子,再是鞋子,由于裤子、衣服、鞋子种类很多,故搭配种类就更多了。又如制作蛋糕,鲜奶油蛋糕、草莓蛋糕或生日蛋糕其实都是蛋糕,这是装饰手法不同而已。因此,如果在程序中采用简单的各个类顺序调用的方法为其装饰,那么程序就会显得相当不灵活,其他的可维护性、可扩展性、可复用性也可想而知了。对此,我们可以采用装饰模式:

说明:

ü  Component定义了一个对象接口,可以给这些对象动态地添加职责;

ü  ConcreteComponent定义了一个具体的对象,也可以给这个对象添加一些职责;

ü  Decorator定义了装饰抽象类,继承了Component,从外类来扩展Component类的

功能,但对于Component来说,无需知道Decorator的存在的,至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能;

ü  SetComponent是用来对对象进行包装(以及再包装的,实际中也可以使用构造函数实

),这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中(之所以能被添加到对象链当中,在于每个ConcreteDecorator都实现了Decorator,而Decorator又实现了Component,故每个装饰好的东西自然可以看作新的装饰,然后作为参数的形式传进去,这样做最大的好处在于:装饰的顺序可以随意定,待装饰好后再展示最后的装饰结果”)

ü  程序中如果只有一个ConcreteComponent类而没有抽象的Component类,那么

Decorator类可以是ConcreteComponent的一个子类。同样道理,如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把DecoratorConcreteDecorator的责任合并成一个类。

实例一:外出打扮

Ø  抽象类 -- 文件Decorator.java

package com.yilong.decorator;

public abstract class Decorator {

    public abstract void show();

}

Ø  装扮对象Person -- 文件Person.java – 最基本(起初)的装扮对象

package com.yilong.decorator;

public class Person extends Decorator {

    private String name;

    public Person(String name) {

       this.name = name;

    }

    public void show() {

       System.out.println(this.name + " - 装扮成功!");

    }

}

Ø  抽象类PersonDecorator – PersonDecorator.java – 各种装扮的抽象

package com.yilong.decorator;

public abstract class PersonDecorator extends Decorator {

    Decorator decorator;

    public PersonDecorator(Decorator decorator) {

       this.decorator = decorator;

    }

    public abstract void show();

}

Ø  文件BigTrouserDisplay.java -- 添加垮裤的装扮

package com.yilong.decorator;

public class BigTrouserDisplay extends PersonDecorator {

    public BigTrouserDisplay(Decorator decorator) {

       super(decorator);

    }

    @Override

    public void show() {

       System.out.println("穿上 垮裤");

       this.decorator.show();

    }

}

Ø  文件TShirtDisplay.java – 添加”T-Shirt”的装扮

package com.yilong.decorator;

public class TShirtDisplay extends PersonDecorator {

    public TShirtDisplay(Decorator decorator) {

       super(decorator);

    }

    @Override

    public void show() {

       System.out.println("穿上 T-Shirt");

       this.decorator.show();

    }

}

Ø  文件Main.java – 测试类

package com.yilong.decorator;

public class Main {

    public static void main(String[] args) {

       Decorator decorator = new TShirtDisplay

(new BigTrouserDisplay(new Person("逸龙")));

       decorator.show();

    }

}

打印结果:

穿上 T-Shirt

穿上 垮裤

逸龙 - 装扮成功!

说明:程序中完全可以实现先穿垮裤,再穿T-Shirt,只要改变顺序即可。

实例二:修饰字符串

Ø  文件Main.java

package com.yilong.decorator.string;

public class Main {

    public static void main(String[] args) {

       Display d1 = new StringDisplay("Hello World!");

        System.out.println("展示方式一:");

       d1.show();

       Display d2 = new SideBorder(d1, '#');

       System.out.println("展示方式二:");

       d2.show();

       Display d3 = new FullBorder(d2);

       System.out.println("展示方式三:");

       d3.show();

       Display d4 = new FullBorder(new SideBorder(d3, '*'));

       System.out.println("展示方式四:");

       d4.show();

    }

}

Ø  文件Display.java

package com.yilong.decorator.string;

public abstract class Display {

    public abstract int getColumns();

    public abstract int getRows();

    public abstract String getRowText(int row);

   

    public void show() {

       for(int i=0; i<getRows(); i++) {

           System.out.println(getRowText(i));

       }

    }

}

Ø  文件StringDisplay.java – 基本的字符串显示

package com.yilong.decorator.string;

public class StringDisplay extends Display {

    private String string;

    public StringDisplay(String string) {

       this.string = string;

    }

    @Override

    public int getColumns() {

       //return string.getBytes().length;//返回字符串字节数

       return string.length();//返回字符串实际长度

    }

    @Override

    public String getRowText(int row) {

       if(row == 0) {

           return string;

       } else {

           return null;

       }

    }

    @Override

    public int getRows() {

       return 1;

    }

}

Ø  文件Border.java – 为字符串添加装饰的抽象类

package com.yilong.decorator.string;

public abstract class Border extends Display {

    protected Display display;

   

    public Border(Display display) {

       this.display = display;

    }

}

Ø  文件SideBorder.java – 为字符串两边添加标志字符显示

package com.yilong.decorator.string;

public class SideBorder extends Border {

    private char borderChar;

    public SideBorder(Display display, char borderChar) {

       super(display);

        this.borderChar = borderChar;

    }

    @Override

    public int getColumns() {

       return this.display.getColumns() + 2;

    }

    @Override

    public String getRowText(int row) {

       return borderChar + this.display.getRowText(row) + borderChar;

    }

 

    @Override

    public int getRows() {

       return this.display.getRows();

    }

}

Ø  文件FullBorder.java – 为字符串添加边框显示的类

package com.yilong.decorator.string;

public class FullBorder extends Border {

    public FullBorder(Display display) {

       super(display);

    }

    @Override

    public int getColumns() {

       return this.display.getColumns() + 2;

    }

    @Override

    public String getRowText(int row) {

       if(row == 0 || row == display.getRows()+1) {

           return "+" + makeLine('-', getColumns()) + "+";

       } else {

           return "|" + this.display.getRowText(row-1) + "|";

        }

    }

    @Override

    public int getRows() {

       return display.getRows() + 2;

    }

    public StringBuffer makeLine(char ch, int count) {

       StringBuffer strb = new StringBuffer();

       for(int i=0; i<count; i++) {

           strb.append("-");

       }

       return strb;

    }

}

打印结果:

展示方式一:

Hello World!

展示方式二:

#Hello World!#

展示方式三:

+----------------+

|#Hello World!#|

+----------------+

展示方式四:

+--------------------+

|*+----------------+*|

|*|#Hello World!#|*|

|*+----------------+*|

+--------------------+

    总结:装饰模式是为已有功能动态地添加更多功能的一种方式;装饰模式把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章