设计模式与应用:装饰模式

本文介绍结构、demo、使用场景选用、与代理模式的区别对比

简介

Decorator模式又叫包装模式。

通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案

在原有方法上包装更多的方法。通过子类包装。核心是子类扩展父类。类比于代理、springAOP。区别于继承的扩展。横向扩展性强

结构图

装饰模式

角色和职责

  • 抽象组件角色:一个抽象接口,是被装饰类装饰父类的接口
  • 具体组件角色:作为抽象组件的实现类
  • 抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口
  • 具体装饰角色:为抽象装饰角色的实现类。负责具体的装饰

实现

本demo是对car的功能进行装饰。也就是扩展车的功能。横向扩展。

UML图如:
demo类图

被装饰的接口

package com.mym.designmodel.decorator;

/**
 * 职责:Component
 */
public interface Car {
    public void show();

    public void run();
}

被装饰的接口的一个具体实现类

package com.mym.designmodel.decorator;

/**
 * 职责 :ConcreteComponent.具体组件角色
 */
public class RunCar implements Car{
    @Override
    public void show() {
        this.run();
    }
    @Override
    public void run() {
        System.out.println("车车可以run!");
    }
}

开始装饰
装饰抽象组件

package com.mym.designmodel.decorator;

/**
 * 职责 :Decorator 抽象接口,装饰规则。
 */
public abstract class CarDecorator implements Car{
    Car car = null;

    public CarDecorator(Car car){
        this.car = car;
    }

    public abstract void show();//具体要装饰的方法

    @Override
    public void run() {
        this.getCar().run();//不做任何处理,我们装饰的是show方法,其他方法就先放过
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }
}

具体装饰类1

package com.mym.designmodel.decorator;

/**
 * 职责:ConcreteDecorator 具体装饰实现
 */
public class SwimCarDecorator extends CarDecorator{
    public SwimCarDecorator(Car car){
        super(car);
    }

    @Override
    public void show() {
        this.getCar().show();
        this.swim();
    }

    public void swim(){
        System.out.println("车车可以swim!");
    }
}

具体装饰类2

package com.mym.designmodel.decorator;

/**
 * 职责:ConcreteDecorator 具体装饰实现
 */
public class FlyCarDecorator extends CarDecorator{

    public FlyCarDecorator(Car car){
        super(car);
    }

    @Override
    public void show() {
        car.show();
        this.fly();
    }

    public void fly(){
        System.out.println("车车可以fly!");
    }
}

测试:

package com.mym.designmodel.decorator;

public class Test {
    public static void main(String[] args) {
        Car car = new RunCar();
        car.show();
        System.out.println("---------------------");
        Car swimCarDecorator = new SwimCarDecorator(car);
        swimCarDecorator.show();
        System.out.println("---------------------");
        Car flyCarDecorator = new FlyCarDecorator(swimCarDecorator);
        flyCarDecorator.show();
    }
}

执行结果

车车可以run!
---------------------
车车可以run!
车车可以swim!
---------------------
车车可以run!
车车可以swim!
车车可以fly!

一般使用场景

需要对一个类功能扩展的地方

优缺点

  • 横向扩展非常方便
  • 同样是会有很多子类

对比代理模式

代理模式详细可以查看另一博文
这里简单讨论一下区别(参考网上很多思考,然后这里做个小总结):

关注点

  • 装饰器模式关注于在一个对象上动态的添加方法
  • 代理模式关注于控制对对象的访问

也可理解为:
- 代理模式,代理类可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。
- 装饰模式,通常是将原始对象作为一个参数传给装饰者的构造器。

方法增强时机

  • 代理模式,代理和真实对象之间的的关系通常在编译时就已经确定
  • 装饰模式,装饰者能够在运行时递归地被构造

使用场景

  • 用装饰模式,一般意味着增加功能:装饰模式:对被装饰的对象增加额外的职责,满足里氏代换原则(子类可以代替父类)。
    • 如,自行车可以脚踏骑车,装饰模式使用后,可能装饰了电动功能,就像大街上有的那种又可以脚踏又可以电动的自行车,装饰最基本的是保证原始功能正常使用。
  • 用代理模式,一般意味着在限制使用:代理模式是修改被代理对象的行为。
    • 如权限判断,权限即是限制。如网吧上网,网管代理你的访问,并会限制访问一些资源

用户(使用)角度

场景设置:A类是原始功能的类, B是装饰模式中对A类的扩展类,C是代理模式中对A类的扩展类

那么对于用户调用来说:
- 使用装饰模式,用户更关系的是B的功能(包含A的原始功能)。

  • 使用代理模式,用户更关心A的功能。并不关系C的功能。

选用方向

  • 扩展一个类的功能时,用装饰
  • 对有的方法进行改进,用代理

猜你喜欢

转载自blog.csdn.net/maoyuanming0806/article/details/80168967
今日推荐