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