装饰者模式定义
动态地将责任附加到对象上。若要扩展功能,装饰者提供比继承更有弹性的替代方案实现类图
装饰者模式的特点
A 装饰者和被装饰对象有相同的超类型。(注意这是利用继承达到”类型匹配“,而不是利用继承获得”行为“,行为来自装饰者和基础组件,或者与其他装饰者之间的组合关系)
B 可以用一个或多个装饰者包装一个对象。
C 因为装饰者和被装饰者具有相同的类型,所以任何需要原始对象的场合,可以用装饰过的对象代替。
D 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
E 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象装饰者模式实现例子
例子1
interface Widget { void draw(); } // 1. "lowest common denominator"
class TextField implements Widget { // 3. "Core" class with "isa" rel
private int width, height;
public TextField( int w, int h ) {
width = w;
height = h;
}
public void draw() {
System.out.println( "TextField: " + width + ", " + height );
} }
// 2. Second level base class
abstract class Decorator implements Widget { // with "isa" relationship
private Widget wid; // 4. "hasa" relationship
public Decorator( Widget w ) { wid = w; }
public void draw() { wid.draw(); } // 5. Delegation
}
class BorderDecorator extends Decorator { // 6. Optional embellishment
public BorderDecorator( Widget w ) {
super( w );
}
public void draw() {
super.draw(); // 7. Delegate to base class
System.out.println( " BorderDecorator" ); // and add extra stuff
} }
class ScrollDecorator extends Decorator { // 6. Optional embellishment
public ScrollDecorator( Widget w ) {
super( w );
}
public void draw() {
super.draw(); // 7. Delegate to base class
System.out.println( " ScrollDecorator" ); // and add extra stuff
} }
//装饰者可以在所委托被装饰者的行为之前或者之后,加上自己的行为,以达到特定的目的
public class DecoratorDemo {
public static void main( String[] args ) {
// 8. Client has the responsibility to compose desired configurations
Widget aWidget = new BorderDecorator(
new BorderDecorator(
new ScrollDecorator(
new TextField( 80, 24 ))));
aWidget.draw();
} }
输出结果为:TextField: 80, 24
ScrollDecorator
BorderDecorator
BorderDecorator
对比python装饰模式实现的一个类似程序
def bread(func):
def wrapper():
print "</''''''\>"
func()
print "<\______/>"
return wrapper
def ingredients(func):
def wrapper():
print "#tomatoes#"
func()
print "~salad~"
return wrapper
@bread
@ingredients
def sandwich(food="--ham--"):
print food
if (__name__=="__main__"):
sandwich()
例子2:编写自己的java I/O装饰器,能够实现将文本中的大写字母转换成小写
JAVA I/O类就是利用装饰者模式来实现诸多的读取方式,InputStream是装饰者中的抽象组件。FilterInputStream是一个抽象装饰者,LIneNumberInputStream是一个具体装饰者,加上了计算行数的能力,BufferInputStream是一个加上缓冲输入功能和readline()方法的具体装饰者
import java.io.*;
class LowerCaseInputStream extends FilterInputStream{
public LowerCaseInputStream (InputStream in) {
super(in);
}
//必须实现两个read方法 一个针对字节 一个针对字节数组
public int read() throws IOException {
int c = super.read();
return (c == -1 ? c : Character.toLowerCase((char) (c)));
}
public int read(byte[] b,int offset,int len) throws IOException {
int result = super.read(b, offset, len);
for(int i =offset; i < offset + result ; i++){
b[i] = (byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}
public class InputTest {
public static void main(String[] args) {
int c;
try{
InputStream in = new LowerCaseInputStream(
new BufferedInputStream(
new FileInputStream("test.txt") ) );
while((c = in.read() ) >= 0) {
System.out.print((char)c);
}
in.close();
}catch (IOException e){
e.printStackTrace();
}
}
例3:编写实现不同种类咖啡加上不同配料的计价程序
//抽象组件饮料
abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
//具体组件 一种咖啡
class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}
class DarkRoast extends Beverage {
public DarkRoast() {
description = "Dark Roast Coffee";
}
public double cost() {
return .99;
}
}
class HouseBlend extends Beverage {
public HouseBlend() {
description = "House Blend Coffee";
}
public double cost() {
return .89;
}
}
//装饰者抽象类
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
//具体装饰者牛奶
class Milk extends CondimentDecorator {
Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
public double cost() {
return .10 + beverage.cost();
}
}
//具体装饰者摩卡
class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return .20 + beverage.cost();
}
}
//具体装饰者奶泡
class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return .10 + beverage.cost();
}
}
public class StarbuzzCoffee {
public static void main(String args[]) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()
+ " $" + beverage.cost());
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription()
+ " $" + beverage2.cost());
Beverage beverage3 = new HouseBlend();
beverage3 = new Soy(beverage3);
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
System.out.println(beverage3.getDescription()
+ " $" + beverage3.cost());
}
}