装饰模式——七种结构型模式之一

1.前言

面向对象三大基本特征中就有继承,表现了对代码的重用和对新功能的扩展。代理模式很好地完成了代码重用,功能都是由被代理者提供,它只负责判断是否调用。就像你住在一个房子里,外人都知道去那找你,但见你前得先进门。
  而装饰模式则可以引入新功能,替代继承关系,所以,能不能增加功能或者改进功能就是装饰模式与代理模式的区别。

2.概念

装饰模式指动态地给一个对象添加一些额外的职责。所谓动态,就是在定义类的时候,不明确声明与别的类或者接口的关系。由于装饰模式基础是代理模式,而代理模式在结构上组合了原始对象,所以与原始对象没有硬性的联系,可以比子类更加灵活地添加功能。

3.场景

李四准备买房,但是工作太忙,只好委托中介。他向中介说明买房的条件,并要求中介在签约前一定要到现场看房,签约后将协议带给他。

4.写法

由于增加的功能很单一,可以直接在代理模式的基础上完成。

// 1.声明需要代理的操作
public interface Buyer {
    
    void buy();

}
// 2.被代理者实现操作
public class LiSi implements Buyer {

    @Override
    public void buy() {
        System.out.println("我要买这套房");
    }

}
// 3.代理者调用被代理者的方法
public class Middleman implements Buyer {
    
    private Buyer customer;

    public Middleman(Buyer customer) {
        super();
        this.customer = customer;
    }

    @Override
    public void buy() {
        // 可以在调用被代理者方法前后附加动作
        System.out.println("中介已到现场看房");
        customer.buy();
        System.out.println("中介已签协议并带回");
    }

}
public class Main {

    public static void main(String[] args) {
        // 由中介完成所有事
        Buyer liSi = new LiSi();
        Buyer middleman = new Middleman(liSi);
        middleman.buy();
    }

}

这里强调一下,上面的代码是在代理模式下改的,有些称谓不对。第一点中声明需要代理的操作,其实是声明抽象组件,可以是抽象类或接口;第二点中被代理者实现操作,其实是实现具体组件;第三点中代理者调用被代理者的方法,其实是实现具体装饰
  既然强调添加功能的灵活性,那就考虑不同条件下有不同的额外功能。李四要求若是新房,条件不变;若是二手房,则必须自己亲自去看。

// 1.抽象装饰者
public abstract class Agency implements Buyer {
    
    private Buyer customer;

    public Agency(Buyer customer) {
        super();
        this.customer = customer;
    }
    
    @Override
    public void buy() {
        // 子类重写实现不同装饰逻辑
        customer.buy();
    }

}
// 2.具体装饰者
public class FirstAgency extends Agency {

    public FirstAgency(Buyer customer) {
        super(customer);
    }
    
    @Override
    public void buy() {
        // 新房的装饰逻辑
        System.out.println("中介已到现场看房");
        super.buy();
        System.out.println("中介已签协议并带回");
    }

}
public class SecondAgency extends Agency {

    public SecondAgency(Buyer customer) {
        super(customer);
    }
    
    @Override
    public void buy() {
        // 二手房的装饰逻辑
        System.out.println("李四亲自到场看房");
        super.buy();
    }

}
public class Main {

    public static void main(String[] args) {
        Buyer liSi = new LiSi();
        // 附加新房的要求
        Buyer first = new FirstAgency(liSi);
        first.buy();
        // 附加二手房的要求
        Buyer second = new SecondAgency(liSi);
        second.buy();
    }

}

实现了子类的作用,但是却没有破坏类的层次结构,仅仅是将原类和新方法封装在了一起。举个例子,曹操挟天子以令诸侯,他没有皇族血脉,但是可以自由地行使皇命。

5.总结

装饰模式能够具有这样的特性,主要还是在于它的结构。使用组合关系,获取原有对象的访问权,并添加自己的方法。可以发现,自讲解结构型模式开始,组合这个概念就不断出现,它是使用对象模式的基础。

    原文作者:lanceJin
    原文地址: https://www.jianshu.com/p/aea936f11530
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞