装饰模式(Decorator Pattern):动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
装饰模式结构:
①.Component: 定义一个对象接口,可以给这些对象动态的添加职责,也叫抽象的Component;
②.ConcreteComponent:定义了一个具体的对象,也可以给这个对象添加一些职责,继承Component,也叫具体的Component;
③.Decorator:装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无须知道Decorator的存在的。
④.ConcreteDecorator:具体的装饰对象类,起到给Component添加职责的功能,继承Component,并且可以有多个。
核心思路: 我们把需要展示的功能按预期的顺序串联起来进行控制。
正如书中小菜的疑惑那样,当需求中看起来并没有执行类必须定义成接口或者抽象类时,是不是上面的结构模式就被破坏?大鸟给出了很好的建议,如果只有一
个 ConcreteComponent类,那么Decorator类可以是ConcreteComponent的一个子类,同样道理,如果只有一个ConcreteDecorator,那么就没有必要再建立一个单独
的 Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。
这里说的是一种替代思想,也就是里氏代换原则:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且他察觉不到父类对象和子类对象的区别,也就是说在软件里把父类都替换成他的子类,程序的行为没有发生变化,即子类必能够替换他们的父类型。也就是说,我们用子类也能实现对应的功能。
好了,我们接下来试一下代码吧,也许看完代码你就豁然开朗。
本文依旧用 Java 来完成代码的展示。
1、顺着书中的意思:我们直接定义一个ConcreteComponent类:
package controller; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; /** * Created by Administrator on 2017/8/2. */ @AllArgsConstructor @NoArgsConstructor public class Person { private String name; public void display(){ System.out.println("是"+ name + "今天的打扮"); } }
2、定义一个ConcreteDecorator 总类(看清楚这里说的是总类) Dress,这个类原本应该继承Decorator,且Decorator继承Component,现在Component没有了,也不需要再定义Decorator了,所以直接继承Component的子类ConcreteComponent,在这里我们就需要继承Person这个类:
package operation; import controller.Person; /** * Created by Administrator on 2017/8/2. */ public class Dress extends Person { Person component; /** * 装饰模式的核心:找模特进行装饰 * @param component 模特 */ public void decorate(Person component){ this.component = component; } /** * 重写display(),实际上执行的是 Person 的 dispplay()--- component.display(); */ @Override public void display(){ if (null != component){ component.display(); } } }
3、分别定义多个ConcreteDecorator 分类(看清楚这里说的是分类),分类直接继承总类 Dress即可:
package entity; import operation.Dress; /** * Created by Administrator on 2017/8/2. */ public class BlackClothes extends Dress { @Override public void display() { System.out.println("黑色的衣服"); super.display(); } }
package entity; import operation.Dress; /** * Created by Administrator on 2017/8/2. */ public class GrayShoes extends Dress { @Override public void display() { System.out.println("灰色的鞋子"); super.display(); } }
package entity; import operation.Dress; /** * Created by Administrator on 2017/8/2. */ public class GrayTrousers extends Dress { @Override public void display() { System.out.println("灰色的长裤"); super.display(); } }
package entity; import operation.Dress; /** * Created by Administrator on 2017/8/2. */ public class RedClothes extends Dress { @Override public void display() { System.out.println("红色的衣服"); super.display(); } }
package entity; import operation.Dress; /** * Created by Administrator on 2017/8/2. */ public class RedShoes extends Dress { @Override public void display() { System.out.println("红色的鞋子"); super.display(); } }
package entity; import operation.Dress; /** * Created by Administrator on 2017/8/2. */ public class WhiteClothes extends Dress { @Override public void display() { System.out.println("白色的衣服"); super.display(); } }
package entity; import operation.Dress; /** * Created by Administrator on 2017/8/2. */ public class WhiteShoes extends Dress { @Override public void display() { System.out.println("白色的鞋子"); super.display(); } }
package entity; import operation.Dress; /** * Created by Administrator on 2017/8/2. */ public class WhiteTrousers extends Dress { @Override public void display() { System.out.println("白色的长裤"); super.display(); } }
4、至此,需要做的准备工作已经完成,接下来测试,也就是装饰及展示效果的过程,定义测试类:
import controller.Person; import entity.*; import operation.Dress; import org.junit.Test; /** * Created by Administrator on 2017/8/2. */ public class TestDress { @Test public void testDress(){ /** * 模特出来了,二哥,初始状态没有装饰 */ Person pp = new Person("二哥"); WhiteClothes whiteClothes = new WhiteClothes(); GrayTrousers grayTrousers = new GrayTrousers(); WhiteShoes whiteShoes = new WhiteShoes(); /** * 装饰过程,把衣物一件件装饰到模特身上 * 可以看到,核心就是装饰品找模特进行装饰的过程 */ whiteClothes.decorate(pp); grayTrousers.decorate(whiteClothes); whiteShoes.decorate(grayTrousers); /** * 后台已经打扮完成,出来展示效果了 */ whiteShoes.display(); } }
展示效果如下:
装饰模式总结:
适用需求描述:当系统需要新功能的时候,是向旧的类中添加新的代码,这些新添加的代码,通常装饰了原有类的核心职责或者主要行为,这种在主类中增加新字段,新方法,新逻辑的做法增加了主类的复杂度,然而,这心新添加的内容仅仅是为了满足一些或者某种情况的使用,让主类没有选择的机会。
装饰模式是为已有功能动态的添加更多功能的一种方式。他把每个需要装饰的功能放在单独的类中,并让这个类包装他所要的装饰对象,因此当需要使用特殊需求时,客户代码就可以在运行时有选择的,按顺序的使用装饰功能包装对象,相当于放宽了条件让你自由选择。
装饰模式的优点:把类中的装饰功能从类中搬移出去,这样可以简化原有的类,并且把类的核心职责和装饰功能分开了,同时去除相关类中的重复装饰的逻辑。
相当于在本例中,造了一大批分类继承Dress这个总类,而不是直接在Dress这个总类中写所有的。
好了,到此,装饰模式基本结束。