装饰器模式是什么
装饰器模式是向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。 装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。
装饰器模式能干什么
我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀,在不想增加很多子类的情况下扩展类选用装饰器模式。
装饰器模式优缺点
优点
1、装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
2、通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果。
3、装饰器模式完全符合开闭原则。
缺点
多层装饰比较复杂:装饰器模式会增加许多子类,过度使用会增加程序得复杂性。
装饰器模式结构
抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
辅助图示
示例代码
1、抽象构件
public interface Component { void operation(); }
2、具体构件
public class ConcreteComponentEat implements Component{ @Override public void operation() { System.out.println("吃东西"); } }
3、抽象装饰者
public class DecoratorEat implements Component{ private Component component; public DecoratorEat(Component component) { this.component = component; } @Override public void operation() { component.operation(); } }
4、具体装饰者
import java.util.Random; public class ConcreteDecoratorTwoEat extends DecoratorEat { public ConcreteDecoratorTwoEat(Component component) { super(component); } @Override public void operation() { super.operation(); addNewOperation(); } /** * 新增功能 */ public void addNewOperation() { if (new Random().nextInt(10) > 5) { System.out.println("加点老干妈,美滋滋。"); } System.out.println("无情干饭人,继续吃!"); } }
import java.util.Random; public class ConcreteDecoratorOneEat extends DecoratorEat { public ConcreteDecoratorOneEat(Component component) { super(component); } @Override public void operation() { super.operation(); addNewOperation(); } /** * 新增功能 */ public void addNewOperation(){ if (new Random().nextInt(10) <= 5){ System.out.println("噎住了!喝口水。"); } System.out.println("无情干饭人,继续吃!"); } }
5、Client
public class TestClient { public static void main(String[] args) { Component p = new ConcreteComponentEat(); p.operation(); System.out.println("----------"); new DecoratorEat(new ConcreteDecoratorOneEat(p)).operation(); System.out.println("----------"); new DecoratorEat(new ConcreteDecoratorTwoEat(p)).operation(); } }
运行结果
吃东西 ---------- 吃东西 噎住了!喝口水。 无情干饭人,继续吃! ---------- 吃东西 加点老干妈,美滋滋。 无情干饭人,继续吃!