1 装饰模式概述

装饰模式

装饰模式动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生产子类更加灵活。

什么时候用到?

当系统需要新的功能时,需要向旧的类中添加新的代码(装饰代码)。但是这样增加了主类的复杂度,而且这些新加的代码可能仅仅是为了在某些特定的情况下才会执行的代码。如果子类不适合扩展,或扩展功能需要的子类太多,可以使用装饰模式来组合对象。
而这时候就需要装饰模式。好处如下:

好处

装饰模式把代码放在单独的类中,这样在客户端需要这些装饰功能的时候,就可以有选择地、按顺序地使用装饰功能包装对象了。
即:有效地把类的核心代码和装饰代码分离,去除相关类中的装饰逻辑。

2 模式结构图

Java技术常用设计模式(七)---  装饰模式_java

组成:
Component类:抽象组件,可以为其动态添加职责。
ConcreteComponent类:具体组件,定义的具体对象,组件的实现类。
Decorator类:抽象装饰类。用来装饰组件;
ConcreteObserver:具体的装饰对象

3 装饰者模式Java代码的实现

Java代码如下:
1)抽象组件

public interface Beverage {
public void drink();
}

2)具体组件:

/**
* 具体的对象---未加任何配料的Coco饮料
* @author GenshenWang.nomico
*/
public class CocoBeverage implements Beverage{

public String name = "";
public CocoBeverage(String name){
this.name = name;
}
@Override
public void drink() {
System.out.println("开始饮用" + name);
}
}


/**
* 具体的对象---未加任何配料的一点点饮料
* @author GenshenWang.nomico
*/
public class YidiandianBeverage implements Beverage{

public String name = "";
public YidiandianBeverage(String name){
this.name = name;
}
@Override
public void drink() {
System.out.println("开始饮用" + name);
}
}

3)抽象装饰类:

public abstract class Decorator implements Beverage{

private Beverage beverage;
public void decorate(Beverage beverage){
this.beverage = beverage;
}
@Override
public void drink(){
if(beverage != null){
beverage.drink();
}
}
}

4)具体装饰类:

public class BlackTeaDecorator extends Decorator{

private String name = "红茶";

@Override
public void drink() {
System.out.println("添加配料:"+ name);
super.drink();
}
}


public class ChocolateMilkDecorator extends Decorator{

private String name = "巧克力奶茶";

@Override
public void drink() {
System.out.println("添加配料:"+ name);
super.drink();
}
}

5)测试:

public class Main {

public static void main(String[] args) {
String beverageName = "好喝的一点点";
Beverage yidiandianBeverage = new YidiandianBeverage(beverageName);
Beverage cocoBeverage = new CocoBeverage(beverageName);

Decorator chocolateMilk = new ChocolateMilkDecorator();
Decorator blackTea = new BlackTeaDecorator();

//装饰一点点奶茶
chocolateMilk.decorate(yidiandianBeverage);
blackTea.decorate(chocolateMilk);
blackTea.drink();

//装饰COCO奶茶
chocolateMilk.decorate(cocoBeverage);
blackTea.decorate(chocolateMilk);
blackTea.drink();
}
}

输出:

添加配料:红茶
添加配料:巧克力奶茶
开始饮用好喝的一点点
添加配料:红茶
添加配料:巧克力奶茶
开始饮用好喝的一点点

4 Java I/O中装饰模式的实现

Java 的 I/O 操作类大概可以分成四组,分别是:
基于字节操作的 I/O 接口:InputStream 和 OutputStream
基于字符操作的 I/O 接口:Writer 和 Reader
基于磁盘操作的 I/O 接口:File
基于网络操作的 I/O 接口:Socket

Java I/O中使用了装饰者模式:

Java技术常用设计模式(七)---  装饰模式_java_02

如上图,
Component抽象组件类: InputStream;
ConcreteComponent具体组件类: FileInputStream,StringBufferInputStream,ButeArrayInputStream;
Decorator抽象装饰类: FilterInputStream;
ConcreteDecorator具体装饰类: BufferedInputStream,PushbackInputStream,DataInputStream,LineNumberInputStream

5 装饰者模式的应用:编写 一个装饰者,将输入流内的所有大写字符转成小写。

1)写一个具体的装饰类:

/**
* 具体装饰类
* @author GenshenWang.nomico
*/
public class LowerCaseInputStream extends FilterInputStream{

protected LowerCaseInputStream(InputStream in) {
super(in);
}

@Override
public int read() throws IOException{
int c = super.read();
return (c == -1) ? c : Character.toLowerCase((char)c);
}
}

2)测试

public class InputTest {

public static void main(String[] args) {
String content = "I AM WGS,A JAVAER HOT FANS";
int c = 0;
InputStream in = null;
try{
in = new LowerCaseInputStream(new BufferedInputStream(new ByteArrayInputStream(content.getBytes("UTF-8"))));
while((c = in.read()) != -1){
System.out.print((char)c);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

输出:

i am wgs,a javaer hot fans


参考:
(1)《大话设计模式》
(2)《Head First 设计模式》