`

DECORATOR(装饰) -—— 对象机构型模式

 
阅读更多
1、意图
    动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更加灵活。
2、别名
    包装器Wrapper
3、动机
    有时我们希望给某个对象而不是整个类添加一些功能。例如,一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些特性,例如边框,或是一些行为,例如窗口滚动。
    使用继承机制是添加功能的一种有效途径,从其他类继承过来的边框特性可以被多个子类的实例所使用。但这种方式不够灵活,因为边框的选择是静态的,用户不能控制对组件加边框的方式和时机。
    一种较为灵活的方式是将组件嵌入另一个对象中,由这个对象添加边框。我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。它将客户请求转发给该组件,并且可能在转发前后执行一些额外的动作(例如画一个边框)。透明性使得你可以递归的嵌套多个装饰,从而可以添加任意多的功能。
    例如,假定有一个对象TextView,它可以在窗口中显示正文。缺省的TextView没有滚动条,因为我们可能有时并不需要滚动条。当需要滚动条时,我们可以用ScrollDecorator添加滚动条。如果我们还想在TextView周围添加一个粗黑边框,可以使用BoarderDecorator添加。因此只要简单地将这些装饰和TextView进行组合,就可以达到预期的效果。
    下面的对象图展示了如何将一个TextView对象与BoarderDecorator以及ScrollDecorator对象组装起来产生一个具有边框和滚动条的文本显示窗口。



   ScrollDecorator和BorderDecorator类是Decorator类的子类。Decorator类是一个可视组件的抽象类,用于装饰其他可视组件,如下图所示:


    VisualComponent是一个描述可视对象的抽象类,它定义了绘制和事件处理的接口。注意Decorator类怎样将绘制请求简单地发送给它的组件,以及Decorator的子类如何扩展这个操作。
    Decorator的子类为特定功能可以自由地添加一些操作。例如,如果其他对象知道界面中恰好有一个ScrollDecorator对象,这些对象就可以用ScrollDecorator对象的ScrollTo操作滚动这个界面。这个模式有一点很重要,它使得在VisualComponent可以出现的任何地方都可以有装饰。因此,客户通常不会感觉到装饰过的组件与未装饰过的组件之间的差异,也不会与装饰产生任何依赖关系。
4、适用性
     以下情况使用Decorator模式
     在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
     处理那些可以撤销的职责。
     当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合奖产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
5、结构




6、参与者
Component(VisualComponent)
    定义一个对象接口,可以给这些对象动态地添加职责。
ConcreteComponent(TextView)
    定义一个对象,可以给这个对象添加一些职责。
Decorator
    维持一个指向Component对象的指针,并定义一个与Component接口一致的接口
ConcreteDecorator(BorderDecorator,ScrollDecorator)
    向组件添加职责
7、协作
    Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作。
8、代码示例


First Example (window/scrolling scenario)

The following Java example illustrates the use of decorators using the window/scrolling scenario.
// the Window interface class
public interface Window {
    public void draw(); // draws the Window
    public String getDescription(); // returns a description of the Window
}
 
// extension of a simple Window without any scrollbars
class SimpleWindow implements Window {
    public void draw() {
        // draw window
    }
 
    public String getDescription() {
        return "simple window";
    }
}

The following classes contain the decorators for all Window classes, including the decorator classes themselves.

// abstract decorator class - note that it extends Window
abstract class WindowDecorator implements Window {
    protected Window decoratedWindow; // the Window being decorated
 
    public WindowDecorator (Window decoratedWindow) {
        this.decoratedWindow = decoratedWindow;
    }
    public void draw() {
        decoratedWindow.draw(); //delegation
    }
    public String getDescription() {
        return decoratedWindow.getDescription(); //delegation
    }
}
 
// the first concrete decorator which adds vertical scrollbar functionality
class VerticalScrollBarDecorator extends WindowDecorator {
    public VerticalScrollBarDecorator (Window decoratedWindow) {
        super(decoratedWindow);
    }
 
    @Override
    public void draw() {
        super.draw();
        drawVerticalScrollBar();
    }
 
    private void drawVerticalScrollBar() {
        // draw the vertical scrollbar
    }
 
    @Override
    public String getDescription() {
        return super.getDescription() + ", including vertical scrollbars";
    }
}
 
// the second concrete decorator which adds horizontal scrollbar functionality
class HorizontalScrollBarDecorator extends WindowDecorator {
    public HorizontalScrollBarDecorator (Window decoratedWindow) {
        super(decoratedWindow);
    }
 
    @Override
    public void draw() {
        super.draw();
        drawHorizontalScrollBar();
    }
 
    private void drawHorizontalScrollBar() {
        // draw the horizontal scrollbar
    }
 
    @Override
    public String getDescription() {
        return super.getDescription() + ", including horizontal scrollbars";
    }
}

Here's a test program that creates a Window instance which is fully decorated (i.e., with vertical and horizontal scrollbars), and prints its description:

public class DecoratedWindowTest {
    public static void main(String[] args) {
        // create a decorated Window with horizontal and vertical scrollbars
        Window decoratedWindow = new HorizontalScrollBarDecorator (
                new VerticalScrollBarDecorator(new SimpleWindow()));
 
        // print the Window's description
        System.out.println(decoratedWindow.getDescription());
    }
}


The output of this program is "simple window, including vertical scrollbars, including horizontal scrollbars". Notice how the getDescription method of the two decorators first retrieve the decorated Window's description and decorates it with a suffix.
Second Example (coffee making scenario)

The next Java example illustrates the use of decorators using coffee making scenario. In this example, the scenario only includes cost and ingredients.

// The abstract Coffee class defines the functionality of Coffee implemented by decorator
public abstract class Coffee {
    public abstract double getCost(); // returns the cost of the coffee
    public abstract String getIngredients(); // returns the ingredients of the coffee
}
 
// extension of a simple coffee without any extra ingredients
public class SimpleCoffee extends Coffee {
    public double getCost() {
        return 1;
    }
 
    public String getIngredients() {
        return "Coffee";
    }
}

The following classes contain the decorators for all Coffee classes, including the decorator classes themselves..

// abstract decorator class - note that it extends Coffee abstract class
public abstract class CoffeeDecorator extends Coffee {
    protected final Coffee decoratedCoffee;
    protected String ingredientSeparator = ", ";
 
    public CoffeeDecorator(Coffee decoratedCoffee) {
        this.decoratedCoffee = decoratedCoffee;
    }
 
    public double getCost() { // implementing methods of the abstract class
        return decoratedCoffee.getCost();
    }
 
    public String getIngredients() {
        return decoratedCoffee.getIngredients();
    }
}
 
// Decorator Milk that mixes milk with coffee
// note it extends CoffeeDecorator
class Milk extends CoffeeDecorator {
    public Milk(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }
 
    public double getCost() { // overriding methods defined in the abstract superclass
        return super.getCost() + 0.5;
    }
 
    public String getIngredients() {
        return super.getIngredients() + ingredientSeparator + "Milk";
    }
}
 
// Decorator Whip that mixes whip with coffee
// note it extends CoffeeDecorator
class Whip extends CoffeeDecorator {
    public Whip(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }
 
    public double getCost() {
        return super.getCost() + 0.7;
    }
 
    public String getIngredients() {
        return super.getIngredients() + ingredientSeparator + "Whip";
    }
}
 
// Decorator Sprinkles that mixes sprinkles with coffee
// note it extends CoffeeDecorator
class Sprinkles extends CoffeeDecorator {
    public Sprinkles(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }
 
    public double getCost() {
        return super.getCost() + 0.2;
    }
 
    public String getIngredients() {
        return super.getIngredients() + ingredientSeparator + "Sprinkles";
    }
}


Here's a test program that creates a Coffee instance which is fully decorated (i.e., with milk, whip, sprinkles), and calculate cost of coffee and prints its ingredients:

public class Main {
 
    public static final void main(String[] args) {
        Coffee c = new SimpleCoffee();
        System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
 
        c = new Milk(c);
        System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
 
        c = new Sprinkles(c);
        System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
 
        c = new Whip(c);
        System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
 
        // Note that you can also stack more than one decorator of the same type
        c = new Sprinkles(c);
        System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
    }
 
}




  • 大小: 20.8 KB
  • 大小: 54.6 KB
  • 大小: 24.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics