- 装饰器模式(Decorator Pattern)
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类较为灵活。
有时我们希望给某个对象而不是整个类添加一些功能。例如,一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些特性,例如边框,或是一些行为,例如窗口滚动。
使用继承可以实现添加功能,但是这样做不够灵活,比较灵活的方式是将组件嵌入另一个对象中,有这个对象添加边框,我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此他对使用该组件的客户透明。
这个模式有一点很重要,用户通常感受不到装饰过的组件和未装饰过的组件之间的差异,也不会与装饰产生任何依赖关系。
以下情况适用装饰模式:
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可以撤销的职责。
- 当不能采用生成子类的方法进行扩充时,一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类的数量呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
示例:
Window.java
public interface Window { void draw(); // Draws the Window String getDescription(); // Returns a description of the Window }
SimipleWindow.java
public class SimpleWindow implements Window { @Override public void draw() { // Draw window } @Override public String getDescription() { return "simple window"; } }
WindowDecorator.java
public class WindowDecorator implements Window { protected Window windowToBeDecorated; // the Window being decorated public WindowDecorator (Window windowToBeDecorated) { this.windowToBeDecorated = windowToBeDecorated; } @Override public void draw() { windowToBeDecorated.draw(); //Delegation } @Override public String getDescription() { return windowToBeDecorated.getDescription(); //Delegation } }
VerticalScrollBarDecorator.java
public class VerticalScrollBarDecorator extends WindowDecorator { public VerticalScrollBarDecorator (Window windowToBeDecorated) { super(windowToBeDecorated); } @Override public void draw() { super.draw(); drawVerticalScrollBar(); } private void drawVerticalScrollBar() { // Draw the vertical scrollbar } @Override public String getDescription() { return super.getDescription() + ", including vertical scrollbars"; } }
HorizontalScrollBarDecorator.java
public class HorizontalScrollBarDecorator extends WindowDecorator { public HorizontalScrollBarDecorator (Window windowToBeDecorated) { super(windowToBeDecorated); } @Override public void draw() { super.draw(); drawHorizontalScrollBar(); } private void drawHorizontalScrollBar() { // Draw the horizontal scrollbar } @Override public String getDescription() { return super.getDescription() + ", including horizontal scrollbars"; } }
DecoratedWindowTest.java
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()); } }
示例2:
Troll.java
public interface Troll { void attack(); int getAttackPower(); void fleeBattle(); }
SimpleTroll.java
public class SimpleTroll implements Troll { @Override public void attack() { System.out.println("The troll tries to grab you!"); } @Override public int getAttackPower() { return 10; } @Override public void fleeBattle() { System.out.println("The troll shrieks in horror and runs away!"); } }
ClubbedTroll.java
public class ClubbedTroll implements Troll { private Troll decorated; public ClubbedTroll(Troll decorated) { this.decorated = decorated; } @Override public void attack() { decorated.attack(); System.out.println("The troll swings at you with a club!"); } @Override public int getAttackPower() { return decorated.getAttackPower() + 10; } @Override public void fleeBattle() { decorated.fleeBattle(); } }
App.java
public class App { /** * Program entry point * * @param args command line args */ public static void main(String[] args) { // simple troll System.out.println("A simple looking troll approaches."); Troll troll = new SimpleTroll(); troll.attack(); troll.fleeBattle(); System.out.println("Simple troll power " + troll.getAttackPower()); // change the behavior of the simple troll by adding a decorator System.out.println("A troll with huge club surprises you."); Troll clubbedTroll = new ClubbedTroll(troll); clubbedTroll.attack(); clubbedTroll.fleeBattle(); System.out.println("Clubbed troll power " + clubbedTroll.getAttackPower()); } }
示例3:
Coffee.java
public interface Coffee { public double getCost(); // Returns the cost of the coffee public String getIngredients(); // Returns the ingredients of the coffee }
CoffeeDecorator.java
public abstract class CoffeeDecorator implements Coffee{ protected final Coffee decoratedCoffee; public CoffeeDecorator(Coffee c) { this.decoratedCoffee = c; } public double getCost() { // Implementing methods of the interface return decoratedCoffee.getCost(); } public String getIngredients() { return decoratedCoffee.getIngredients(); } }
SimpleCoffee.java
public class SimpleCoffee implements Coffee { @Override public double getCost() { return 1; } @Override public String getIngredients() { return "Coffee"; } }
WithMilk.java
public class WithMilk extends CoffeeDecorator { public WithMilk(Coffee c) { super(c); } public double getCost() { // Overriding methods defined in the abstract superclass return super.getCost() + 0.5; } public String getIngredients() { return super.getIngredients() + ", Milk"; } }
WithSprinkles.java
public class WithSprinkles extends CoffeeDecorator { public WithSprinkles(Coffee c) { super(c); } public double getCost() { return super.getCost() + 0.2; } public String getIngredients() { return super.getIngredients() + ", Sprinkles"; } }
Main.java
public class Main { public static void printInfo(Coffee c) { System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients()); } public static void main(String[] args) { Coffee c = new SimpleCoffee(); printInfo(c); c = new WithMilk(c); printInfo(c); c = new WithSprinkles(c); printInfo(c); } }
架构师成长营