装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
上面引用来自百度百科,装饰模式,通过一个装饰类来包裹真实对象,先关注几个点:
不改变原类文件
不使用继承
动态扩展
下面这张类图也是来自百度百科,我先写装饰模式,后面再扩展一些东西。
Component:待装饰的接口
ConcreteComponent:待装饰的原始类,实现了待装饰接口
Decorator:装饰抽象父类,继承待装饰接口
ConcreteDecorator:装饰子类,实现装饰功能
最近在看手机,所以我打算用手机这个例子来实现一下装饰模式
//待装饰接口
public interface Phone {
//买手机方法
void buy();
}
//待装饰原始类,实现了待装饰接口
public class MiPhone implements Phone {
@Override
public void buy() {
System.out.println("买了一部小米");
}
}
//抽象装饰类
public abstract class Decorator implements Phone {
private Phone phone;
//构造方法,传入待装饰原始类
public Decorator(Phone phone) {
this.phone = phone;
}
@Override
public void buy() {
phone.buy();
}
}
//装饰子类-手机壳(类)
public class KeConcreteDecorator extends Decorator {
public KeConcreteDecorator(Phone phone) {
super(phone);
}
public void buy() {
super.buy();
System.out.println("买了一个漂亮的手机壳给手机套上");
}
}
//装饰子类-手机膜(类)
public class MoConcreteDecorator extends Decorator {
public MoConcreteDecorator(Phone phone) {
super(phone);
}
public void buy() {
super.buy();
System.out.println("买了张钢化膜给手机贴上");
}
}
下面是客户端调用
//客户端
public class DecoratorDemo {
public static void main(String[] args) {
//创建小米手机实例
Phone phone = new MiPhone();
//1.只买了手机壳
Decorator ke = new KeConcreteDecorator(phone);
ke.buy();
System.out.println("================================");
//2.只买了手机膜
Decorator mo = new MoConcreteDecorator(phone);
mo.buy();
System.out.println("================================");
//3.同时买了手机壳和手机膜
Decorator mo2 = new MoConcreteDecorator(ke);
mo2.buy();
}
}
这里演示了三种情况
装饰模式和静态代理模式
初初看装饰模式的时候,瞬间冒出一个想法,这模式跟代理模式很像哦。
跟原始类解耦
无论是装饰类或者是代理类,发现都是在不改动原始类的基础上,附加新的功能客户端调用方式很像
示例中代理类和装饰类的时候,都是传入了那个具体的对象。
下面来解答上面两个问题
是解耦应该没错,在不改动原始类的基础上,实现同一个(待装饰或被代理)接口。但是思想观念上面有一个很大区别。
装饰模式:
强调的是增强
客户端主动行为
客户端主动的行为。像上面的例子,客户端买到了一个小米手机,是一个裸机,打算花点钱买手机壳或手机膜装饰一下手机,可以根据客户端的想法选择装饰。但这是在程序在运行的时候,才增强的功能(装饰)。
静态代理模式:
强调的是限制
客户端被动行为
(上图创建userManager的时候,其实是不严谨的,因为我将需要代理的具体对象暴露了出来。创建的具体实例应该在代理类的构造方法中完成)使用静态代理模式模式的时候,客户端是无感的(被动),即客户端并不知道是哪个真实对象(被代理类)。所以在编译阶段,代理类已经指定了使用哪个被代理类(限制)。
现在又回到最上方那句引用有3个关注点
第一点就很清楚了。
第二点,“不使用继承”。
public class KeDemo extends MiPhone {
public void buy() {
super.buy();
System.out.println("买了一个漂亮的手机壳给手机套上");
}
}
public class MoDemo extends MiPhone{
public void buy() {
super.buy();
System.out.println("买了张钢化膜给手机贴上");
}
}
public class ClientDemo {
public static void main(String[] args) {
MoDemo md = new MoDemo();
md.buy();
System.out.println("====================");
KeDemo kd = new KeDemo();
kd.buy();
}
}
第二点是不能使用这种继承方式,虽然能实现部分的功能,但是就不能达到第三点的要求了,“动态扩展”。这个动态扩展怎么理解?像上面装饰模式的客户端中第三种使用方法,可以将另外一种装饰子类作为构造方法的参数传递(由于他们的顶级父类都是phone),可以同时实现多种装饰,这就是动态扩展了。
装饰模式就介绍到这里了,谢谢大家。