装饰者模式,又叫做包装模式,指的是不改变原有对象的基础上,把功能附加在对象上。提供了比继承更加有弹性的扩展方案,属于结构型设计模式。
1,从一个例子开始
相信很多人都玩过《和平精英》这个游戏。在游戏中,玩家可以自由地捡一些枪械和部件,并把部件安装到枪械上,自由地组合一把枪以提升枪的功能,这其实就是装饰者模式的一个体现。
今天我们就来模拟一下这个例子。
首先创建一个枪械抽象类:
packagecom.gitee.swsk33.decorator.model; importlombok.Getter; importlombok.Setter; /*** 枪械*/publicabstractclassGun { /*** 名字*/privateStringname; /*** 当前武器状态*/privateStringstatus; /*** 武器性能*/privateintcapability; }
然后创建具体枪械类-98K步枪:
packagecom.gitee.swsk33.decorator.model.impl; importcom.gitee.swsk33.decorator.model.Gun; /*** 98K步枪*/publicclassKar98KextendsGun { /*** 构造函数:初始化属性*/publicKar98K() { setName("Kar98K"); setStatus("98K步枪"); setCapability(10); } }
好了,假设要给这个步枪加上八倍镜,那有的人可能会在这个类基础上又创建一个类Kar98KWithEightfoldScope
并修改其参数,再加上一个子弹袋,就又创建一个类。。。
很显然这是不行的,在游戏中枪械和部件种类非常的多,而每一把枪和很多部件可以玩出多种组合,如果把每个组合都列举一遍,显然是非常不现实的。
这时,就要用到装饰者模式了。
2,创建装饰者抽象类和具体类
在这里,枪械部件都称之为装饰者,因为它们可以动态扩展枪械功能,枪械就是被装饰者。
创建装饰者的抽象:
packagecom.gitee.swsk33.decorator.wrapper; importcom.gitee.swsk33.decorator.model.Gun; /*** 枪的部件*/publicabstractclassGunWrapperextendsGun { /*** 传入要安装部件的枪械*/privateGungun; /*** 构造器依赖注入** @param gun 要安装部件的枪械*/publicGunWrapper(Gungun) { this.gun=gun; } }
然后实现具体的装饰者。
八倍镜:
packagecom.gitee.swsk33.decorator.wrapper.impl; importcom.gitee.swsk33.decorator.model.Gun; importcom.gitee.swsk33.decorator.wrapper.GunWrapper; /*** 八倍镜部件*/publicclassEightfoldScopeextendsGunWrapper { /*** 构造器依赖注入** @param gun 要安装部件的枪械*/publicEightfoldScope(Gungun) { super(gun); this.setStatus(gun.getStatus() +" + 八倍镜"); this.setCapability(gun.getCapability() +5); } }
子弹袋:
packagecom.gitee.swsk33.decorator.wrapper.impl; importcom.gitee.swsk33.decorator.model.Gun; importcom.gitee.swsk33.decorator.wrapper.GunWrapper; /*** 子弹袋部件*/publicclassBulletBagextendsGunWrapper { /*** 构造器依赖注入** @param gun 要安装部件的枪械*/publicBulletBag(Gungun) { super(gun); this.setStatus(gun.getStatus() +" + 子弹袋"); this.setCapability(gun.getCapability() +3); } }
这里可见:装饰者抽象类中有一个属性就是被装饰者,因为我们要先把被装饰者传入给装饰者实例,装饰者才能对被装饰者进行操作和附加。然后具体的装饰者,就会对传入的被装饰者进行一个功能的附加。
就像你要把具体的一个物品放进礼物盒子一样,礼物盒子就是装饰者。
我们来运行一下:
// 模拟玩家正在吃鸡游戏// 捡到一把98K步枪Gunkar98k=newKar98K(); System.out.println("当前武器情况:"+kar98k.getStatus() +",性能:"+kar98k.getCapability()); // 捡到一个八倍镜并安装至98K上面kar98k=newEightfoldScope(kar98k); System.out.println("当前武器情况:"+kar98k.getStatus() +",性能:"+kar98k.getCapability()); // 捡到一个子弹袋并安装至98K上面kar98k=newBulletBag(kar98k); System.out.println("当前武器情况:"+kar98k.getStatus() +",性能:"+kar98k.getCapability());
结果:
3,总结
可见装饰者模式,可以很灵活地对原有的对象进行扩展,我们需要什么装饰,就实例化什么装饰并附加给被装饰物,是非常的方便灵活的。
可见装饰者模式中,有以下类:
- 抽象被装饰者:上面的枪械抽象类
- 具体被装饰者:上面的98K类
- 抽象装饰者:上面的部件抽象类
- 具体装饰者:上面的八倍镜、子弹袋类
通常使用装饰者接收被装饰者实例,在装饰者中对被装饰者实例进行功能附加,就完成了装饰的步骤。上述例子比较简单,就在构造函数中对被装饰者进行了附加。很多时候在装饰者中会重写被装饰者的某个成员方法实现功能附加。
并且,具体被装饰者和抽象装饰者都有着共同的超类(父类):抽象被装饰者。这样使得装饰之后的实例,仍然属于最初的类型。
装饰者模式的类图如下: