首页 > 编程笔记 > Java笔记

装饰器模式和代理模式的区别

从 UML 类图和实现代码上看,代理模式与装饰器模式几乎一模一样。代理模式的 Subject 对应装饰器模式的 Component,代理模式的 RealSubject 对应装饰器模式的 Concrete Component,代理模式的 Proxy 对应装饰器模式的 Decorator。

确实,从实现代码的角度看,代理模式的确与装饰器模式是一样的(其实装饰器模式就是代理模式的一个特殊应用),但是这两种设计模式所面向的功能扩展面是不一样的。

装饰器模式强调自身功能的扩展。Decorator 所做的就是增强 Concrete Component 的功能(也有可能减弱功能),主体对象为 Concrete Component,着重类功能的变化。

代理模式强调对代理过程的控制。Proxy 完全掌握对 RealSubject 的访问控制,因此,Proxy 可以决定对 RealSubject 进行功能扩展、功能缩减甚至功能散失(不调用 RealSubject 方法),主体对象为 Proxy。

实例说明

下面通过举例,针对两者的区别进行探讨。

假设现在小明想租房,那么肯定需要搜索房源、联系房东谈价格等事情。

1. 基础实现

首先定义一个租房的接口,代码如下:
public interface RentHouse {
    void renting();
}
创建人(小明)类实现租房接口。
public class People implements RentHouse {
    @Override
    public void renting() {
        System.out.println("小明租房");
    }
}

2. 代理模式

按照代理模式进行思考,小明只需要找到一个房产中介,让中介去做房源搜索、联系房东这些事情,小明只需等待通知就可以了。

新建房屋中介(代理)类。
public class HouseAgent implements RentHouse{

    private People people;

    public HouseAgent(People people){
        this.people=people;
    }
    @Override
    public void renting() {
        System.out.println("房产中介搜索房源");
        people.renting();
        System.out.println("房产中介联系房东");
    }
}
测试类如下:
public static void main(String[] args) {
    // 代理模式
    People people = new People();
    RentHouse rentHouse = new HouseAgent(people);
    rentHouse.renting();
}
运行结果如下:

房产中介搜索房源
小明租房
房产中介联系房东

3. 装饰器模式

如果采用装饰器模式进行思考,因为装饰器模式强调的是自身功能扩展,也就是说,如果要租房子,小明自身就要增加搜索房源、联系房东能力扩展。通过相应的装饰器,提升自身能力,一个人做完所有的事情。

修改 HouseAgent(抽象装饰角色)类,代码如下:
public class HouseAgent implements RentHouse {

    private People people;

    public HouseAgent(People people) {
        this.people = people;
    }

    @Override
    public void renting() {
        //System.out.println("房产中介搜索房源");
        people.renting();
        //System.out.println("房产中介联系房东");
    }
}
新建 PowerfulXiaoMing(具体装饰角色)类,代码如下:
public class PowerfulXiaoMing extends HouseAgent {
    public PowerfulXiaoMing(People people) {
        super(people);
    }

    @Override
    public void renting() {
        super.renting();
        addSkill();
    }

    public void addSkill() {
        System.out.println("搜索房源");
        System.out.println("联系房东");
    }
}
测试类代码如下:
public static void main(String[] args) {
    // 装饰器模式
    People people = new People();
    HouseAgent rh = new PowerfulXiaoMing(people);
    rh.renting();
}
运行结果如下:

小明租房
搜索房源
联系房东


由以上实例可以总结出:

对于代理类,如何调用对象的某一功能是思考重点,不需要兼顾对象的所有功能;对于装饰类,如何扩展对象的某一功能是思考重点,同时也需要兼顾对象的其它功能,因为再怎么装饰,本质也是对象本身,要担负起对象应有的职责。由于被装饰者的职责一旦增加,装饰类也需要有相应的扩展,所以必然会造成编码的负担,增加程序的复杂性。

设计模式就是为了提升代码的可扩展性,灵活应用即可,没有必要生搬硬套,非要分出个所以然来,装饰器模式和代理模式的区别也是如此。

所有教程

优秀文章