装饰器模式(DecoratorPattern)DecoratorPattern可以实现为对象动态添加功能,也就是从一个对象的外部给对象添加功能。给一个类或对象添加行为通常有两种方式:继承机制,使用继承机制是为已有类添加功能的有效方式,通过继承一个已有的类,子类可以同时拥有自己的方法它也有父类的方法。但是这个方法是静态的,用户无法控制添加行为的方式和时机。组合机制是将一个类的对象嵌入到另一个对象中,由另一个对象决定是否调用嵌入对象的行为,以扩展自身的行为。我们称这个嵌入对象为装饰器(Decorator)。显然,为了扩展对象的功能,频繁修改父类或派生子类是不可取的。在面向对象设计中,我们应该尽量使用对象组合而不是对象继承来扩展和重用功能。装饰器模式是基于对象组合的方式,可以灵活的给对象添加需要的功能。装饰者模式的本质是动态组合。动态是手段,组合是目的。简而言之,装饰模式就是将复杂的功能进行简化和分散,然后在运行时根据需要动态组合的模式。装饰者模式定义装饰者模式:动态地给一个对象添加一些额外的职责(Responsibility)。在添加对象函数方面,装饰模式比生成子类实现更灵活。它的别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但适用于不同的场合。根据不同的翻译,装饰模式也称为“画家模式”,是一种对象结构模式。装饰模式的优点装饰模式和继承关系的目的是为了扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。可以动态扩展一个对象的功能,可以在运行时通过配置文件选择不同的装饰器来实现不同的行为。通过使用不同的具体装饰器和这些装饰器的排列,可以创建许多不同行为的组合。您可以使用多个具体装饰类来装饰同一个对象以获得更强大的对象。模式结构和描述聚合关系用带空心菱形箭头的直线表示。上图是Component聚合到Decorator,或者Decorator由Component组成。继承关系直接用空心箭头表示。要了解UML类图,请参阅此文档。Component:组件对象的接口,可以动态地为这些对象添加职责;这个对象通常是装饰器装饰的原始对象,你可以给这个对象添加职责;Decorator:所有装饰器的父类,需要定义一个与Component接口一致的接口(主要是实现装饰器功能的复用,即一个特定的装饰器A可以装饰另一个特定的装饰器B,因为装饰器类也是一个Component)并持有一个Component对象,它实际上是被装饰的对象。如果不继承Component接口类,则只能为组件添加单一功能,即装饰器对象不能装饰其他装饰器对象。ConcreteDecorator:具体的装饰器类,实现特定的功能,添加到被装饰对象中。用于装饰一个特定的组件对象或另一个特定的装饰器对象。装饰器示例代码1.组件抽象类,可以为这些对象动态添加职责'|'.__方法__。"\r\n";}}3。装饰器的抽象类维护了一个指向组件对象的接口对象,并定义了一个与组件接口一致的接口/***传入构造方法*/publicfunction__construct(Component$component){$this->component=$component;}abstractpublicfunctionoperation();}4.装饰器的具体实现类,给组件对象添加职责,beforeOperation(),afterOperation()是前后添加的职责。classConcreteDecoratorAextendsDecorator{//在调用父类的操作方法之前publicfunctionbeforeOperation(){echo__CLASS__.'|'.__方法__。"\r\n";}//调用父类的operation方法post-operationpublicfunctionafterOperation(){echo__CLASS__.'|'.__方法__。"\r\n";}publicfunctionoperation(){$this->beforeOperation();$this->component->operation();//这里可以选择性的调用父类的方法。如果不调用,相当于完全重写了方法,实现了一个新函数$this->afterOperation();}}classConcreteDecoratorBextendsDecorator{//调用父类operation方法的前置操作publicfunctionbeforeOperation(){echo__CLASS__.'|'.__方法__。"\r\n";}//调用父类的operation方法后publicfunctionafterOperation(){echo__CLASS__.'|'.__方法__。"\r\n";}publicfunctionoperation(){$this->beforeOperation();$this->component->operation();//这个是可选调用父类的方法。如果不调用,相当于完全重写了方法,实现了新函数$this->;操作后();}}5.客户端使用装饰器类Client{publicfunctionmain(){$component=newConcreteComponent();$decoratorA=newConcreteDecoratorA($component);$decoratorB=newConcreteDecoratorB($decoratorA);$decoratorB->操作();}}$client=newClient();$client->main();6、运行结果oncreteDecoratorB|ConcreteDecoratorB::beforeOperationConcreteDecoratorA|ConcreteDecoratorA::beforeOperationConcreteComponent|ConcreteComponent::operationConcreteDecoratorA|ConcreteDecoratorA::afterOperationConcreteDecoratorB|ConcreteDecoratorB::afterOperation装饰方式需要注意。装饰器的接口必须与被装饰类的接口相同。对客户来说,装修前的对象和装修后的对象都尽量处理。保持具体组件类ConcreteComponent的轻量化,不要把辅助逻辑和状态放在具体组件类的主要逻辑之外,可以通过装饰类进行扩展。如果只有一个具体构件类,没有抽象构件类,那么抽象装饰类可以作为具体构件类的直接子类。适用环境需要在不影响组件对象的情况下,以动态、透明的方式向对象添加职责。当系统不能通过继承进行扩展或者继承不利于系统的扩展和维护时,可以考虑装饰类。本文已收录在Laravel源码学习系列文章中,欢迎访问阅读。
