Decorator 装饰模式,对象结构模式,动态的给对象添加额外的职责。就增加功能而言,Decorator 比生成子类更为灵活。
Decorator 又叫wrapper,相当于在原来的物体上面又套了个东西,但是不改变原来的接口。它是对某个对象添加一些功能而不是整个类。比如一个文本套了个边框接口没变,然后又套了个滚动条,接口还是没有变。
Decorator 在actionscript设计模式有讲,他比静态的继承更为灵活、与它的compont不一样,是一个透明的包装可以很容易的添加一个特性。但是,采用Decotor会产生很多的类似的小对象,导致学习它很难,也很难排错。
使用Decorator要注意,接口的一致性,当你只要添加一个职责时,没有必要定义抽象Decorator类,保持装饰对象的简单性。当componen本身就很庞大时,使用Decorator的代价是很高的,strategy会好点。
装饰器模式采用的是组合而不是继承来给对象添加新的行为。
参与者:
Component,定义一对象的接口,可以给这个对象动态的添加职责。
ConcreteComponent,定义一对象,可以给这个对象动态的添加职责。
Decorator,维持一个指向Compoennt的对象引用,并定义一个和Components一致的接口。
ConcreteDecorator,向组件添加行为。
注意,Decorator是要和被装饰的对象有一致的接口的,和Proxy一样,而Adaptor是个接口转换器,两个接口并没有直接的联系。Composite也是一致的接口,他是强调单个和群体,有一致的接口。
下面来举个例子说明下,Decorator是怎么用的:
AdstractBasicShap .as
package {
import flash.display.*;
public class AdstractBasicShap extends Sprite {
public function AdstractBasicShap() {
}
}
}
Cicle .as
package {
import flash.display.*;
public class Cicle extends AdstractBasicShap {
public function Cicle(radius:Number) {
graphics.lineStyle(2,0,1);
graphics.beginFill(0xFFFFFF,0.3);
graphics.drawCircle(radius,radius,radius);
graphics.endFill();
}
}
}
Rectangle.as
package {
import flash.display.*;
public class Rectangle extends AdstractBasicShap {
public function Rectangle(ShapeWidth:Number,
shapHeight:Number,
center:Boolean = false) {
graphics.lineStyle(2,0,1);
graphics.beginFill(0xFFFFFF,0.3);
graphics.drawRect(center? - ShapeWidth/2:0,center?-shapHeight/2:0,ShapeWidth,shapHeight);
graphics.endFill();
}
}
}
DraggableSahpe .as
package {
import flash.display.*;
import flash.events.*;
public class DraggableSahpe extends AdstractBasicShap {
private var decorated:AdstractBasicShap;
public function DraggableSahpe(decorated:AdstractBasicShap) {
addChild(decorated);
addEventListener(MouseEvent.MOUSE_DOWN,onMouseDownHandler);
addEventListener(MouseEvent.MOUSE_UP,onMouseUpHandler);
}
private function onMouseDownHandler(e:MouseEvent):void {
startDrag();
}
private function onMouseUpHandler(e:MouseEvent):void {
stopDrag();
}
}
}
ColorableShape .as
package {
import flash.geom.*;
public class ColorableShape extends AdstractBasicShap {
public function ColorableShape(shape:AdstractBasicShap,
red:uint,green:uint,blue:uint) {
shape.transform.colorTransform = new ColorTransform(red,green,blue);
addChild(shape);
}
}
}
ResizeableShape .as
package {
import flash.events.*;
public class ResizeableShape extends AdstractBasicShap {
private var decorated:AdstractBasicShap;
private var isResizing:Boolean;
private var resizer:AdstractBasicShap;
override public function set width(value:Number):void {
decorated.width = value;
resizer.x = value;
}
override public function set height(value:Number):void {
decorated.height = value;
resizer.y = value;
}
public function ResizeableShape(shape:AdstractBasicShap) {
decorated = shape;
addChild(decorated);
resizer = new Rectangle(10,10,true);
resizer = new ColorableShape(resizer,0.8,0.8,0.8);
resizer.x = decorated.width;
resizer.y = decorated.height;
addChild(resizer);
resizer.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDownHandler);
resizer.addEventListener(MouseEvent.MOUSE_UP,onMouseUpHandler);
}
private function onMouseDownHandler(e:MouseEvent):void {
addEventListener(Event.ENTER_FRAME,onEnterframeHandler);
resizer.startDrag(true);
e.stopImmediatePropagation();
}
private function onMouseUpHandler(e:MouseEvent):void {
resizer.stopDrag();
removeEventListener(Event.ENTER_FRAME,onEnterframeHandler);
}
private function onEnterframeHandler(e:Event):void {
if(resizer.x < 0) {
resizer.x = 0;
}
if(resizer.y < 0) {
resizer.y = 0;
}
decorated.width = resizer.x;
decorated.height = resizer.y;
}
}
}