装饰者模式(Decorator Pattern)
定义
金玉其外, 败絮其中.
动态地给一个对象添加一些额外的职责, 就增加功能来说, 装饰者模式比生成子类更为灵活.--《设计模式: 可复用面向对象软件的基础》
装饰者模式是一种对象结构型模式.
使用场景
在不影响其他对象的情况下, 以动态, 透明的方式给单个对象添加职责.
需要动态地给一个对象增加功能, 这些功能也可以动态地被撤销.
当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时. 不能采用继承的情况主要有两类: 第一类是系统中存在大量独立的扩展, 为支持每一种组合将产生大量的子类, 使得子类数目呈爆炸性增长; 第二类是因为类定义不能继承(如 final 类).
角色
抽象构件角色(Component): 定义一个对象接口或抽象类, 可以给这些对象动态地添加职责.
具体构件角色(ConcreteComponent): 实际被动态地添加职责的对象.
抽象装饰者角色(Decorator): 实现了 Component 接口, 用来扩展 Component 类的功能, 但对于 Component 来说, 是无需知道 Decorator 的存在的.
具体装饰者角色(ConcreteDecorator): 动态地添加职责的对象.
图示
装饰者模式 (Decorator) 结构图
代码示例
装饰者模式 (Decorator) 代码示例类图
这是一个关于相亲的故事. 某家有女初长成, 七大姑八大姨欲帮忙觅得佳婿, 后在各种群, 圈, 网站, 收集了各种男人的资料. 这里需要一个应用生成收集过来的男人的描述, 如: 是否有车, 是否有房, 是否有存款, 是否有好品质. 然后这个应用了装饰者模式的应用就诞生了, 动态添加男人的描述, 最后得到男人的综述.
抽象构件角色(Man.java):
- // 男人
- public interface Man {
- public void getManDesc();
- }
具体构件角色(NormalMan.java):
- // 普通男人
- public class NormalMan implements Man{
- private String name = null;
- public NormalMan(String name) {
- this.name = name;
- }
- @Override
- public void getManDesc() {
- System.out.print(name + ":");
- }
- }
抽象装饰者角色(AttachedPropertiesDecorator.java):
- // 附加属性装饰者
- public abstract class AttachedPropertiesDecorator implements Man{
- private Man man;
- public AttachedPropertiesDecorator(Man man) {
- this.man = man;
- }
- public void getManDesc() {
- man.getManDesc();
- }
- }
具体装饰者角色(CarDecoratorImpl.java,HouseDecoratorImpl.java,DepositDecoratorImpl.java,QualityDecoratorImpl.java):
- // 小车装饰者
- public class CarDecoratorImpl extends AttachedPropertiesDecorator{
- private String car = "有车";
- public CarDecoratorImpl(Man man) {
- super(man);
- }
- public void addCar() {
- System.out.print(car + " ");
- }
- @Override
- public void getManDesc() {
- super.getManDesc();
- addCar();
- }
- }
- // 房子装饰者
- public class HouseDecoratorImpl extends AttachedPropertiesDecorator{
- private String house = "有房";
- public HouseDecoratorImpl(Man man) {
- super(man);
- }
- public void addHouse() {
- System.out.print(house + " ");
- }
- @Override
- public void getManDesc() {
- super.getManDesc();
- addHouse();
- }
- }
- // 存款装饰者
- public class DepositDecoratorImpl extends AttachedPropertiesDecorator{
- private String deposit = "有存款";
- public DepositDecoratorImpl(Man man) {
- super(man);
- }
- public void addDeposit() {
- System.out.print(deposit + " ");
- }
- @Override
- public void getManDesc() {
- super.getManDesc();
- addDeposit();
- }
- }
- // 品质装饰者
- public class QualityDecoratorImpl extends AttachedPropertiesDecorator{
- private String quality = "有好品质";
- public QualityDecoratorImpl(Man man) {
- super(man);
- }
- public void addQuality() {
- System.out.print(quality + " ");
- }
- @Override
- public void getManDesc() {
- super.getManDesc();
- }
- }
有车, 有房, 有存款, 有品质具体修饰者.
装饰者模式测试类(DecoratorTest.java):
- public class DecoratorTest {
- public static void main(String[] args) {
- Man man = new NormalMan("张三");
- Man man1 = new CarDecoratorImpl(man);
- Man man2 = new HouseDecoratorImpl(man1);
- Man man3 = new DepositDecoratorImpl(man2);
- System.out.println("层层装饰:");
- man3.getManDesc();
- System.out.println();
- System.out.println("重复装饰(有两个'有存款'):");
- Man man4 = new DepositDecoratorImpl(man3);
- man4.getManDesc();
- System.out.println();
- System.out.println("任意修饰:");
- Man man5 = new QualityDecoratorImpl(man1);
- man5.getManDesc();
- System.out.println();
- System.out.println("直接得到修饰结果:");
- Man man6 = new HouseDecoratorImpl(new DepositDecoratorImpl(new NormalMan("李四")));
- man6.getManDesc();
- System.out.println();
- }
- }
运行结果:
优点
1, 装饰者模式和继承关系的目的都是要扩展对象的功能, 但是装饰模式可以提供比继承更多的灵活型.
2, 通过使用不同的具体装饰者类及它们不同的组合顺序, 可以得到不同装饰后具有不同行为或者状态的对象. 例如上面的 CarDecoratorImpl 可以多次修饰一个男人, 证明他有很多车.
3, 符合开闭原则.
缺点
1, 增加了抽象装饰者类和具体装饰者类, 一定程度增加了系统的复杂度, 加大了系统的学习和理解成本.
2, 灵活性也意味着更容易出错, 对于多次被多次修饰的对象, 调试时寻找错误可能需要找到多个地方.
- Man man = new NormalMan("张三");
- Man man1 = new CarDecoratorImpl(man);
- Man man2 = new HouseDecoratorImpl(man1);
- Man man3 = new DepositDecoratorImpl(man2);
- Man man = new NormalMan("张三");
- CarDecoratorImpl man1 = new CarDecoratorImpl(man);
- HouseDecoratorImpl man2 = new HouseDecoratorImpl(man);
- DepositDecoratorImpl man3 = new DepositDecoratorImpl(man);
- man1.addCar();
- man2.addHouse();
- man3.addDeposit();
来源: https://www.cnblogs.com/mingmingcome/p/9798248.html