zoukankan      html  css  js  c++  java
  • 设计模式之装饰模式

    一,写在前面
        在学习装饰模式之前,建议先了解代理模式。装饰模式和代理模式的类图结构几乎一样,仅仅是使用的目的有所差异,对比学习有助于理解装饰模式的使用。

        假设有一个接口Human,一个接口的实现类Man。人类Human是可以跑步的,但是不能飞。

        如果想给人类加上飞翔的翅膀,可以有三种解决方案:

    修改实现类Man的方法,但不符合开闭原则
    给实现类Man添加一个子类,扩展一个人类可以飞的功能。问题在于,如果又想给人类增加猎豹般奔跑的速度,需要继续扩展一个子类。显然,使用继承的方式去扩展一个类的功能,会增加类的层级,类的臃肿会加大维护的成本。
    使用装饰模式扩展一个类的功能。好处在于,如果继承关系是纵向的,那么装饰类则是某个类横向的扩展,并不会影响继承链上的其他类。例如:C extends B , B extends A,如果需要扩展B的功能,可以设计一个B的装饰类,它并不会影响B的子类C。如果采用在B里面增加方法,势必会使B的所有子类结构被改变。
    二,装饰模式
    基本步骤:

    定义一个接口Human
    定义一个被装饰的类Man
    定义一个装饰的抽象类,内部持有被装饰类的引用
    定义一个装饰的实现类
    定义一个接口Human,代码如下:

    public interface Human {
    public void run();
    }
    抽取一个抽象方法run,人类是可以跑步的。

    定义一个被装饰的类Man,代码如下:

    public class Man implements Human {
    @Override
    public void run() {
    System.out.println("人会跑步");
    }
    }
    定义一个装饰的抽象类,代码如下:

    public abstract class AbstractDecorator implements Human{
    //持有被装饰类的引用
    private Human human;

    //构造函数注入被装饰者
    public AbstractDecorator(Human human) {
    this.human = human;
    }

    //调用被装饰类的方法
    @Override
    public void run() {
    human.run();
    }
    }
    第3行,模块间的依赖关系,通过成员变量实现,符合迪米特法则。

    第6行,模块间的依赖通过抽象Human产生,而不是通过Man,符合依赖倒置原则。

    定义一个装饰的实现类,代码如下:

    public class ManDecorator extends AbstractDecorator {
    public ManDecorator(Human human) {
    //调用父类的构造方法
    super(human);
    }

    //装饰类增加的功能
    private void fly() {
    System.out.println("人可以飞");
    }

    //增强了功能的run方法
    @Override
    public void run() {
    super.run();
    fly();
    }
    }
    客户端代码如下:

    public class Client {
    public static void main(String[] args) {
    //创建被装饰的类
    Human human = new Man();

    //创建装饰的类,并添加被装饰类的引用
    Human superMan = new ManDecorator(human);

    //执行增强后的run方法
    superMan.run();
    }
    }
    打印结果如下:

    代码里均有详细注释,不再阐述。

    三,使用场景,及优缺点
    使用场景:

    替代继承,扩展一个类的功能
    动态的给一个对象添加功能,以及动态的撤销该功能
    优点:

    动态扩展一个实现类的功能,在不需要添加功能的时候,可以撤销装饰。
    装饰类和被装饰类模块间,通过抽象产生依赖,不会相互耦合
    装饰模式替换继承,可以避免继承链的子类被影响
    四,装饰模式与代理模式的区别
    装饰模式:侧重给一个实现类动态添加功能,不会对实现类的方法进行过滤拦截

    代理模式:侧重将一个实现类的功能,委托给代理类来处理,可以对实现类的方法进行过滤拦截(某种情况下,可能不执行实现类的方法)

    装饰和继承的区别
    https://www.cnblogs.com/losedMemory/p/6246029.html

  • 相关阅读:
    每天一篇经济学人 2020-09-15 分享在 特朗普的“疫苗政治”:科学与政治之争 | 经济学人
    english notes
    new word
    gilbert strang
    news etc
    对自己的要求
    JDBC添加数据
    题目-1031-字符串反转
    题目-1002-字符串分类统计
    ERROR:格式化hdfs后,datanode只启动了一个
  • 原文地址:https://www.cnblogs.com/wangjing666/p/11310660.html
Copyright © 2011-2022 走看看