前言在编码的时候,我们经常会使用继承来扩展一个类。随着扩展功能的增加,子类会越来越多,使得系统变得不灵活。装饰者模式允许在不改变现有对象结构的情况下向现有对象添加新功能。它允许我们在扩展类时保持系统更加灵活。那么装饰者模式究竟是什么样子的呢?从一个场景开始,我们有一块土地。在这块土地上,我们想建一栋有几个房间的别墅。每个房间的装修费用不同。现在,我们需要计算建造别墅的成本。首先定义一个Land类来代表这块土地,Land类定义了在这块土地上建别墅要花钱的规则。abstractclassLand{abstractpublicfunctioncost();}Land已经定义了规则,在这块土地上盖房子要花钱,但是盖一个房间需要多少钱呢?此时,我们又定义了一个Room类,它专门定义了建造一个房间的基本成本(最简单的什么都没有的房间)。classRoomextendsLand{private$money=1000;publicfunctioncost(){返回$this->money;}}然后我们开始建造房间。我们建了两个房间,客厅和餐厅,用LivingRoom类和DiningRoom类来表示classLivingRoomextendsRoom{publicfunctioncost(){returnparent::cost()+200;//客厅的建设成本比房子的建设成本多200,比如买沙发和电视}}classDiningRoomextendsRoom{publicfunctioncost(){returnparent::cost()+100;//餐厅的建设成本比房子的建设成本要多100,比如买张餐桌}}现在,我们可以轻松搞定一个客厅所需的成本$livingRoomCost=newLivingRoom();echo$livingRoomCost->cost();问题来了然而,这样的结构并不灵活,虽然我们可以很容易得出建造一个客厅和一个餐厅的成本,但是如果我买一块小地,只能把餐厅和客厅建在同一块土地上房间,费用如何计算?创建一个包含客厅和餐厅的LivingDiningRoom类是不是还很麻烦?这样做除了麻烦之外,还会造成代码重复。解决问题为了更好的解决这个问题,我们不得不做一些调整。我们还首先声明Land类和Room类。不同的是引入了一个房间装饰类RoomDecorator,它继承了Land类,因为Land类没有实现。cost()方法,所以需要声明为一个抽象类,定义一个以Land类的对象为参数的构造方法,传入的对象会存放在$land属性中,声明为受保护,以便子类访问。详情如下。抽象类RoomDecorator扩展Land{protected$land;公共函数__construct(Land$land){$this->land=$land;}}然后我们重新定义客厅类和餐厅类LivingRoomextendsRoomDecorator{publicfunctioncost(){return$this->land->cost()+200;}}classDiningRoomextendsRoomDecorator{publicfunctioncost(){return$this->land->cost()+100;}}这两个类都继承自RoomDecorator类,这意味着它们都具有对Land对象的引用。当调用它们的cost()方法时,它们会先调用所引用的Land类对象的cost()方法,然后再进行自己特有的操作。所以此时,建造客厅的成本是这样计算的$livingRoomCost=newLivingRoom(newRoom());echo$livingRoomCost->cost();//输出1200建造餐厅的成本是这样计算的$diningRoomCost=newDiningRoom(newRoom());echo$diningRoomCost->cost();//输出1100回到上一个问题,如果我们需要计算建造一个包括客厅和餐厅的房间的成本,代码如下$livingRoom=newDiningRoom(newLivingRoom(newRoom()));echo$livingRoom->cost();//输出为1300,我们现在计算建造成本的方式是:计算基本房间的成本-->在基本房间上面装修客厅的成本-->加上装修客厅的成本diningroomonthebasisofthelivingroom-->得到包括客厅和餐厅在内的房间成本。不再需要创建LivingDiningRoom类来计算包括客厅和餐厅在内的房间的建造成本。这是装饰模式。通过层层装饰,我们可以灵活的得到我们想要的结果。可以轻松添加新的装饰器类或新组件以创建灵活的结构。完整代码money;}}//装饰器abstractclassRoomDecoratorextendsLand{protected$land;公共函数__construct(Land$land){$this->land=$land;}}classLivingRoomextendsRoomDecorator{publicfunctioncost(){return$this->land->cost()+200;}}classDiningRoomextendsRoomDecorator{publicfunctioncost(){return$this->land->cost()+100;}}$livingRoomCost=newLivingRoom(newRoom());echo$livingRoomCost->cost();//输入1200$diningRoomCost=newDiningRoom(newRoom());echo$diningRoomCost->cost();//输出1100$livingDining=newDiningRoom(newLivingRoom(newRoom()));echo$livingDining->cost();//输出1300结束。编码愉快!^_^更多好文,关注公众号获得取
