欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

装饰模式

程序员文章站 2022-05-17 17:18:55
...

本文参考:《修炼Java开发技术:在架构中体验设计模式和算法之美   于广编著》。

 

装饰模式是指给一个类添加一些额外的职责,并且在添加这些额外的职责时不会控制该类的执行逻辑。

装饰模式能够在不必改变原类文件盒使用继承的情况下,动态扩展一个对象的功能。装饰模式是通过创建一个包装对象来实现,也就是用装饰来包裹真实的对象。

 

装饰模式的特点:

1、装饰对象和真实对象有相同的接口,这样客户端对象就能够以与真实对象相同的方式同装饰对象交互。

2、.装饰对象包含一个真实对象的索引(reference)。

3、装饰对象接受所有的来自客户端的请求。它把这些请求转发给真实的对象。

4、装饰对象可以在转发这些请求以前或者以后增加一些附加的功能。

 

装饰模式与类继承的主要区别如下:

 1、装饰模式是一种动态行为,对已经存在的类进行随意组合,而类的继承是一种静态行为,一个类定义成什么样子,其对象便具有什么功能,无法动态的改变。

2、装饰模式扩展的是对象的功能,不需要增加类的数量。而类继承扩展是类的功能,在继承的关系中,如果我们想增加一个对象的功能,我们只能通过继承关系,在子类中增加方法。

3、装饰模式是在不改变原类文件和使用继承的情况下,动态的扩展一个对象的功能,它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

4、装饰模式把对客户端的调用委派给被装饰的类,装饰模式的关键在于这种扩展是完全透明的。

 

举例:

制作蛋糕,蛋糕种类有是奶酪蛋糕、巧克力蛋糕、插花的巧克力蛋糕、贺卡的冰激凌蛋糕等等,在这里我们只需要关注蛋糕,而贺卡、插花只不过是起到了装饰的作用。现在我们想要什么就能生成什么。

package decorator.demo;

/**
 * 蛋糕基类
 *
 */
public abstract class Cake {
	String remark = "蛋糕";
	public String getRemark() {
		return remark;
	}
	public abstract String getImpression();//用来描述吃蛋糕的感觉。。。。
}

 实现装饰器抽象类:

package decorator.demo;

/**
 * 其他用来添加蛋糕的东西
 * @author Nicholas
 *
 */
public abstract class OtherDecorator extends Cake{
	Cake cake;
	/**
	 * 引用一个Cake.
	 * 让被装饰者进入装饰者之中。这里用的是构造方法注入。
	 * 这样就可以调用Cake实例的方法了。
	 * @param cake
	 */
	public OtherDecorator(Cake cake){
		this.cake=cake;
	}
	/**
	 * 让装饰器的子类都去实现getRemark方法。业务需要每个装饰器都要有描述。
	 */
	public abstract String getRemark();
}

 实现一个乳酪蛋糕:

package decorator.demo;
/**
 * 乳酪蛋糕
 */
public class CheeseCake extends Cake{
	/**
	 * 乳酪蛋糕的构造方法
	 */
	public CheeseCake(){
		super.remark="乳酪蛋糕";//修改乳酪蛋糕的描述。
	}

	/**
	 * 实现了Cake抽象类的getImpression
	 * 吃乳酪蛋糕的感觉。。
	 */
	public String getImpression() {
		return "香甜感受";
	}

}

 巧克力蛋糕

package decorator.demo;

/**
 * 巧克力蛋糕
 */
public class ChocolateCake extends Cake{
	public ChocolateCake(){
		super.remark="巧克力蛋糕";
	}


	public String getImpression() {
		return "丝一般的润滑";
	}
}

 冰淇淋蛋糕

package decorator.demo;

/**
 * 冰淇淋蛋糕
 *
 */
public class IceCake extends Cake{
	public IceCake(){
		super.remark="冰淇淋蛋糕";
	}


	public String getImpression() {
		return "冰爽无比";
	}
	
	
}

 贺卡装饰:

package decorator.demo;

public class CardDecorator extends OtherDecorator {

	public CardDecorator(Cake cake) {
		super(cake);
		super.remark = "贺卡";
	}


	public String getImpression() {
		return cake.getImpression()+","+"吃起来口感不错啊!!";
	}
	
	public String getRemark() {
		return cake.getRemark()+"+"+super.remark;
	}

}

 鲜花装饰

package decorator.demo;

/**
 * 给蛋糕添加的花
 */
public class FlowerDecorator extends OtherDecorator{
	
	/**
	 * 构造函数
	 * 传入一个cake实例,也就是前面所实现的Cake的子类,如奶酪蛋糕,巧克力蛋糕等等。
	 * @param cake
	 */
	public FlowerDecorator(Cake cake){
		super(cake);//调用父类的构造方法,可以获取Cake的实例了。就可以调用Cake实例的方法.
		super.remark="一朵玫瑰花";
	}
	
	/**
	 * 实现了装饰器抽象类的getImpression方法。
	 */
	public String getImpression() {
		//这是重点。我们通过构造方法传入的cake实例。对cake进行了装饰,增加了新的功能。
		return cake.getImpression()+","+"看到一朵花真是happy";
	}

	public String getRemark() {
		return cake.getRemark()+"+"+super.remark;
	}
}

 坚果装饰

package decorator.demo;

/**
 * 给蛋糕添加的坚果
 *
 */
public class NutsDecorator extends OtherDecorator{

	public NutsDecorator(Cake cake){
		super(cake);
		super.remark = "果仁";
	}
	
	public String getImpression() {
		return cake.getImpression()+","+"吃起来口感不错啊!!";
	}
	
	public String getRemark() {
		return cake.getRemark()+"+"+super.remark;
	}
}

 美女1喜欢:乳酪蛋糕+一朵玫瑰花+果仁

package decorator.demo;

public class MyGirl {
	public static void main(String[] args){
		Cake cheeseCake = new NutsDecorator(new FlowerDecorator(new CheeseCake()));
		System.out.println("remark "+cheeseCake.getRemark());
		System.out.println("impression "+cheeseCake.getImpression());
	}
}

结果:

remark 乳酪蛋糕+一朵玫瑰花+果仁
impression 香甜感受,看到一朵花真是happy,吃起来口感不错啊!!

 

美女2喜欢用果仁,花包装巧克力蛋糕。

package decorator.demo;

public class MyGirlB {
	public static void main(String[] args){
		//用果仁,花包装巧克力蛋糕。
		Cake nutsFlowerChocolateCake = new NutsDecorator(new FlowerDecorator(new ChocolateCake()));
		System.out.println("remark "+nutsFlowerChocolateCake.getRemark());
		//吃蛋糕的感受已经发生了改变。
		System.out.println("impression "+nutsFlowerChocolateCake.getImpression());
	}
}

 结果:

remark 巧克力蛋糕+一朵玫瑰花+果仁
impression 丝一般的润滑,看到一朵花真是happy,吃起来口感不错啊!!

 

 在Java中流接口和装饰模式的关系

InputStream就是输入流的抽象接口,而FilterInputStream就相当于装饰器。

举例说明:

对英文进行移动2位加密,a->c  y->a z->b

方法一

package decorator.demo;

import java.io.IOException;
import java.io.OutputStream;

public class EncryptOutputStream extends OutputStream {

    private OutputStream os = null;

    public EncryptOutputStream(OutputStream os) {
        this.os = os;
    }

    @Override
    public void write(int a) throws IOException {
        a += 2;
        if (a >= (97 + 26)) {
            a -= 26;
        }
        this.os.write(a);
    }

}

 方法二

package decorator.demo;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class EncryptOutputStream2 extends FilterOutputStream {

    public EncryptOutputStream2(OutputStream os) {
        super(os);
    }

    @Override
    public void write(int a) throws IOException {
        a += 2;
        if (a >= (97 + 26)) {
            a -= 26;
        }
        super.write(a);
    }

}

 测试:

package decorator.demo;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.junit.Test;

public class TestDecorator {

    @Test
    public void test() throws IOException {
        DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(new EncryptOutputStream(
                new FileOutputStream("mytest.txt"))));
        dout.write("abcdxyz".getBytes());
        dout.close();
    }
    
    @Test
    public void test2() throws IOException{
        DataOutputStream dout = new DataOutputStream(new EncryptOutputStream2 (new BufferedOutputStream(
                new FileOutputStream("mytest.txt"))));
        dout.write("abcdxyz".getBytes());
        dout.close();
    }
    
}

 test1和test2的区别在于BufferedOutputStream和EncryptOutputStream2可以在位置上互换,而EncryptOutputStream则不行,因为EncryptOutputStream2继承的是装饰器的父类,使用装饰器提供的功能协助完成想要装饰的功能。而EncryptOutputStream仅仅只是outputStream的子类。

方法二更合理。