装饰模式动态的将责任附加到对象上。就增加功能来说,装饰模式比生成子类更为灵活。装饰模式在GOF95中分类为结构模式。
装饰模式具有以下优点:
装饰模式具有以下缺点:
考虑一个煎饼果子摊位,根据食材的不同进行收费:绿豆面饼皮、杂粮饼皮、玉米饼皮、荞麦饼皮,这些是主料,食客只能选择一种;鸡蛋、鸭蛋、火腿肠、培根、馃子、馃篦、雪菜、葱花、蒜泥、榨菜……等等这些是辅料,可以任意组合,制作成各式各样的煎饼果子。这样的需求如果使用继承来实现,将导致“类爆炸”的发生,而装饰模式却可以很轻松的满足需要:
public class TianjinHamburgerApplication { //食材接口 static interface Material{ //计算价格 int getCost(); } //面皮 abstract static class Sheet implements Material{ } //绿豆面皮 static class GreenBeanSheet extends Sheet{ public int getCost(){ return 2; } } //玉米面皮 static class CornSheet extends Sheet{ public int getCost(){ return 1; } } //辅材,可以任意搭配,以满足不同口味需求 static abstract class Side implements Material{ private Material material; public Side(Material material){ this.material = material; } public int getCost() { return material.getCost(); } } //鸡蛋 static class Egg extends Side{ private int num; public Egg( int num, Material material ){ super(material); this.num = num; } @Override public int getCost() { return super.getCost() + this.num * 1; } } //油条 static class FriedStick extends Side{ public FriedStick( Material material ) { super( material ); } public int getCost() { return super.getCost() + 2; } } //雪菜 static class PickledMustard extends Side{ public PickledMustard( Material material ) { super( material ); } public int getCost() { return super.getCost() + 1; } } public static void main( String[] args ) { //给我来个煎饼果子 Material tianjinHamburger = new GreenBeanSheet(); //来根油条 tianjinHamburger = new FriedStick( tianjinHamburger ); //加十个鸡蛋 tianjinHamburger = new Egg( 10,tianjinHamburger ); //加点雪菜啊 tianjinHamburger = new PickledMustard( tianjinHamburger ); //结账 System.out.println(tianjinHamburger.getCost()); } }
在Java I/O框架中,装饰模式被广泛的使用,以提供缓冲、回退、按行处理等功能,下面是Java I/O框架输入流的部分类图:
其中FilterInputStream是一个抽象的装饰器,它具有InputStream接口,它的子类用来装饰基础的输入流,提供各种功能。除了InputStream以外,OutputStream、Writer、Reader采用了类似的设计。
AOP是一种编程范式,它从另外一个角度考虑程序结构以完善OO。在传统的OO开发中,都是从“纵向”角度分析系统,因此系统架构图都是自上而下,层层依赖。系统的每个业务模块常常分为表现层、逻辑层、数据层。在设计过程中会发现,不同的模块会存在一些公用的功能,例如日志管理、事物管理、安全性检查等。这时候,就应当改为“横向”角度来分析系统,考虑如何把这些公用的功能独立出来实现,以便模块化、重用。AOP框架提供一些原语(切面、切入点、通知等),允许将那些业务无关、但是被业务模块共同调用的逻辑或责任封装起来,减少系统的重复代码,降低模块耦合度。更重要的是,业务模块不知道AOP通用模块的存在,这意味着业务模块和通用模块可以独立演化。
装饰模式与AOP在思想上有共同之处,都可以透明的为业务功能对象增加功能,但是AOP的实现方式更加灵活、可配置,且AOP将主动调用变成了被动织入。
Leave a Reply