装饰器模式的意图是在运行时组合操作的新变化。
动态地给一个对象添加一些额外的职责。相比生成子类更加灵活。
装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能。通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式。显然,直接修改对应的类这种方式并不可取。在面向对象的设计中,而我们也应该尽量使用对象组合,而不是对象继承来扩展和复用功能。
装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能。装饰器模式的本质就是动态组合。动态是手段,组合才是目的。总之,装饰模式是通过把复杂的功能简单化,分散化,然后再运行期间,根据需要来动态组合的这样一个模式。
下面这个例子有助于理解 装饰的流程和作用
现在需要一个汉堡,主体是鸡腿堡,可以选择添加生菜、酱、辣椒等等许多其他的配料,这种情况下就可以使用装饰者模式。
汉堡基类(被装饰者)
package decorator;
public abstract class Humburger {
private String name;
public String getName(){
return this.name;
public abstract double getPrice();
}
鸡腿堡类(被装饰者的初始状态)
package decorator;
public class ChickenBurger extends Humburger{
private String name;
public ChickenBurger() {
this.name="鸡腿堡";
}
@Override
public double getPrice(){
return 10;
}
@Override
public String getName(){
return this.name;
}
}
配料的基类(装饰者,用来对汉堡进行多层装饰,每层装饰增加一些配料)
package decorator;
public abstract class Condiment extends Humburger{
public abstract String getName();
}
生菜(装饰者的第一层)
package decorator;
public class Lettuce extends Condiment{
private Humburger hum;
Lettuce(Humburger hum){
this.hum=hum;
}
@Override
public String getName(){
return hum.getName()+ " 加生菜";
}
@Override
public double getPrice(){
return hum.getPrice()+1.5;
}
}
辣椒(装饰者的第二层)
package decorator;
public class Chilli extends Condiment{
private Humburger hum;
public Chilli(Humburger hum) {
this.hum=hum;
}
@Override
public String getName(){
return hum.getName()+" 加辣椒";
}
@Override
public double getPrice(){
return hum.getPrice(); //辣椒免费
}
}
测试
package decorator;
public class Test {
public static void main(String[] args) {
Humburger hum = new Chilli(new Lettuce(new ChickenBurger()));
System.out.println(hum.getName());
System.out.println(hum.getPrice());
}
}
//结果
鸡腿堡 加生菜 加辣椒
11.5
Component
:组件对象的接口,可以给这些对象动态的添加职责;
ConcreteComponent
:具体的组件对象,实现了组件接口。该对象通常就是被装饰器装饰的原始对象,可以给这个对象添加职责;
Decorator
:所有装饰器的父类,需要定义一个与组件接口一致的接口(主要是为了实现装饰器功能的复用,即具体的装饰器A可以装饰另外一个具体的装饰器B,因为装饰器类也是一个Component),并持有一个Component对象,该对象其实就是被装饰的对象。如果不继承组件接口类,则只能为某个组件添加单一的功能,即装饰器对象不能在装饰其他的装饰器对象。
ConcreteDecorator
:具体的装饰器类,实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象。
组件接口
package decorator;
public interface Human {
public void wearClothes();
public void walk();
}
具体实现接口的对象
package decorator;
public class Person implements Human{
@Override
public void wearClothes() {
System.out.println("穿什么呢");
}
@Override
public void walk() {
System.out.println("去哪里呢");
}
}
装饰器接口(抽象类)
package decorator;
public abstract class Decorator implements Human{
protected Human human;
public Decorator(Human human){
this.human = human;
}
public void wearClothes(){
human.wearClothes();
}
public void walk(){
human.walk();
}
}
装饰器的具体实现对象A、B、C…
package decorator;
public class Decorator_first extends Decorator{
public Decorator_first(Human human) {
super(human);
}
public void goRoom(){
System.out.println("进房子...");
}
public void findMap(){
System.out.println("找地图...");
}
@Override
public void wearClothes(){
super.wearClothes();
goRoom();
}
@Override
public void walk(){
super.walk();
findMap();
}
}
package decorator;
public class Decorator_two extends Decorator{
public Decorator_two(Human human) {
super(human);
}
public void goClothesPress(){
System.out.println("去衣柜找找...");
}
public void findPlaceOnMap(){
System.out.println("在Map上找找...");
}
@Override
public void wearClothes(){
super.wearClothes();
goClothesPress();
}
@Override
public void walk(){
super.walk();
findPlaceOnMap();
}
}
package decorator;
public class Decorator_three extends Decorator{
public Decorator_three(Human human) {
super(human);
}
public void findClothes(){
System.out.println("找到一件衣服");
}
public void findTarget(){
System.out.println("找到目的地");
}
@Override
public void wearClothes(){
super.wearClothes();
findClothes();
}
@Override
public void walk(){
super.walk();
findTarget();
}
}
测试
package decorator;
public class TestHuman {
public static void main(String[] args) {
Human human = new Person();
//链式调用
Decorator decorator = new Decorator_three(
new Decorator_two(new Decorator_first(human)));
decorator.wearClothes();
decorator.walk();
}
}
//结果
穿什么呢
进房子...
去衣柜找找...
找到一件衣服
去哪里呢
找地图...
在Map上找找...
找到目的地
在以下两种情况下可以考虑使用装饰器模式:
(1)需要在不影响其他对象的情况下,以动态、透明的方式给对象添加职责。
(2)如果不适合使用子类来进行扩展的时候,可以考虑使用装饰器模式。
java中的IO是明显的装饰器模式的运用。FilterInputStream
,FilterOutputStream
,FilterRead
,FilterWriter
分别为具体装饰器的父类,相当于Decorator类,它们分别实现了InputStream
,OutputStream
,Reader
,Writer
类(这些类相当于Component,是其他组件类的父类,也是Decorator类的父类)。
继承自InputStream
,OutputStream
,Reader
,Writer
这四个类的其他类是具体的组件类,每个都有相应的功能,相当于ConcreteComponent类。而继承自FilterInputStream
,FilterOutputStream
,FilterRead
,FilterWriter
这四个类的其他类就是具体的装饰器对象类,即ConcreteDecorator
类。通过这些装饰器类,可以给我们提供更加具体的有用的功能。如FileInputStream
是InputStream
的一个子类,从文件中读取数据流,BufferedInputStream
是继承自FilterInputStream
的具体的装饰器类,该类提供一个内存的缓冲区类保存输入流中的数据。我们使用如下的代码来使用BufferedInputStream
装饰FileInputStream
,就可以提供一个内存缓冲区来保存从文件中读取的输入流。
图解如下:
①组件接口,相当于Component:
InputStream
OutputStream
Reader
Writer
②组件的实现类,相当于ConcreteComponent
FileInputStream
③装饰器接口,相当于Decorator
FilterInputStream
FilterOutputStream
FilterRead
FilterWriter
④装饰器类
BufferedInputStream继承自FilterInputStream
使用说明:我们可以用BufferedInputStream修饰FileInputStream
如:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
//其中file为某个具体文件的File或者FileDescription对象
再如:
FileWriter file = new FileWriter("sample.txt");
BufferedWriter writer = new BufferedWriter(file);
writer.write("a small amount of sample text");
writer.newLine();
writer.close();
特点:上述例子的特点是从一个流组合另一个流。