装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
上面引用来自百度百科,装饰模式,通过一个装饰类来包裹真实对象,先关注几个点:
不改变原类文件
不使用继承
动态扩展
下面这张类图也是来自百度百科,我先写装饰模式,后面再扩展一些东西。
Component:待装饰的接口
ConcreteComponent:待装饰的原始类,实现了待装饰接口
Decorator:装饰抽象父类,继承待装饰接口
ConcreteDecorator:装饰子类,实现装饰功能
最近在看手机,所以我打算用手机这个例子来实现一下装饰模式
//待装饰接口public interface Phone {//买手机方法void buy();}
//待装饰原始类,实现了待装饰接口public class MiPhone implements Phone {@Overridepublic void buy() {System.out.println("买了一部小米");}}
//抽象装饰类public abstract class Decorator implements Phone {private Phone phone;//构造方法,传入待装饰原始类public Decorator(Phone phone) {this.phone = phone;}@Overridepublic 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),可以同时实现多种装饰,这就是动态扩展了。
装饰模式就介绍到这里了,谢谢大家。
