本文最后更新于:3 years ago
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于 结构型模式 ,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
我们通过下面的实例来演示装饰器模式的用法。其中,我们将把一个形状装饰上不同的颜色,同时又不改变形状类。
如果想了解修饰器模式的具体的介绍,菜鸟教程介绍得比较详细↓菜鸟教程-修饰器模式
结构图 参考博客
优缺点 优点: 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点: 多层装饰比较复杂。
使用场景 1、扩展一个类的功能。 2、动态增加功能,动态撤销。
实现代码 这里是拿别人的例子来说的,我们都知道坦克大战这个游戏,在游戏设计完了,玩了一段时间后,我觉得游戏里的坦克不够炫,没有别人设计的那种感觉。于是这时,我想给他加一个外壳,加一条尾巴,再加个血条。这酷! 这不难实现吧。但我们要求是,再给坦克发出的子弹也加上一条尾巴和外壳。
方法一(×) 即使不会设计模式,大部分人也能够想到用继承来实现。是的,这是一种方法, 当我们需要加血条是,继承Tank类,实现BloodTank,加尾巴,实现TailTank类,加外壳,实现RectTank类 类似的BloodTailTank、BloodRectTank、TailBullet… 但是缺点在哪里呢?当我们在修饰时,需要继承出来,产生新的类。这时当父类变化时,子类也需要跟着变化。
是不是一下看出来缺点了:
不灵活:装饰和别装饰者之间耦合度太高。
此时就有了进一步的方法
方法二(×) 首先有了tank类,接着将tank和所需添加的装饰聚合到一个TankDecorator类中,接着建立TankDecorator类。
TankDecorator = tank(); paint() -> tank.paint() + 装饰(Blood+Rect+Tail+...)
这么一看是不是比抽象要好很多了。 But,依然不够完美,比如说,我们要将装饰(尾巴,血条)装饰到子弹上,用TankDecorator就不行了,因为里面聚合的是坦克,此时就还需要写一个BulletDecorator类。
方法三(√) 分析 我们采用的就是要说的修饰器模式。
将聚合的tank -> GameObject
此时变为
Decorator = GameObject();
此时Decorator不是专属于子弹或坦克,它是给GameObject做装饰的,所以任何的GameObject都可以和某种具体的Decorator聚合到一起 这时,子弹也可以和某种具体的Decorator聚合到一起。例如,在子弹上添加RectDecorator和TailDecorator,需要做的是,new 一个 RectDecorator,将子弹传入,接着new 一个TailDecorator,将子弹传入进来。
代码 首先创建一个GameObject接口
GameObject.javapublic interface GameObject { void draw () ; }
创建子弹实体类(Bullet)和坦克实体类(Tank)实现 GameObject 接口
Bullet.javapublic class Bullet implements GameObject { @Override public void draw () { System.out.println("GameObject:Bullet" ); } } Tank.javapublic class Tank implements GameObject { @Override public void draw () { System.out.println("GameObject:Tank" ); } }
接着,创建实现了 GameObject 接口的抽象装饰类
GODecorator.javapublic abstract class GODecorator implements GameObject { protected GameObject decoratorGameObject; public GODecorator (GameObject decoratorGameObject) { this .decoratorGameObject = decoratorGameObject; } @Override public void draw () { System.out.println("GameObject:GODecorator" ); } }
创建扩展了 GODecorator 类的实体装饰类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 RectDecorator.javapublic class RectDecorator extends GODecorator { public RectDecorator (GameObject decoratorGameObject) { super (decoratorGameObject); } @Override public void draw () { super .draw(); setRectDecorator(decoratorGameObject); } private void setRectDecorator (GameObject decoratorGameObject) { System.out.println(" + Rect" ); } } TailDecorator.javapublic class TailDecorator extends GODecorator { public TailDecorator (GameObject decoratorGameObject) { super (decoratorGameObject); } @Override public void draw () { super .draw(); setTailDecorator(decoratorGameObject); } private void setTailDecorator (GameObject decoratorGameObject) { System.out.println(" + Tail" ); } }
使用 RectDecorator 和 TailDecorator 来修饰 GameObject 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Main { public static void main (String[] args) { Tank tank = new Tank(); GODecorator rectTank = new RectDecorator(tank); GODecorator tailTank = new TailDecorator(tank); tank.draw(); rectTank.draw(); tailTank.draw(); Bullet bullet = new Bullet(); GODecorator rectTank1 = new RectDecorator(bullet); GODecorator rectTailTank = new TailDecorator(rectTank1); rectTailTank.draw(); } }
执行步骤,输出结果
GameObject:Tank GameObject:GODecorator + Rect GameObject:GODecorator + Tail --------------- GameObject:GODecorator + Tail