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; } } }