1. 为何需要装饰者模式(why)
在我们的工作中,往往会这样的需求,就是动态地将责任附加到对象上,来达到拓展对象功能的目的。例如,对于做饼这件事来说,往往在做好一个饼之后,会有加糖,加盐,加鸡蛋这样类似的客户需求,不同的需求价格当然不同。我们通常的做法创建基类(Cake),然后让其他的子类继承它,试想下,如果如果有很多的类,岂不是会造成类爆炸,新出一款新的饼,就会构造一个类,计算不同的价格。而装饰者模式应用在这上面就非常的好。你想加糖,那我在外面包装一层,把额外的价格加上去。以后如果有几种配料的叠加,不用创造新的类,由原来的子类通过装饰者模式包装起来就行。
2. 如何实现装饰者模式how)
- 定义一个饼的基类,其他的饼的种类继承它。
public abstract class Cake {
public String message="CAKE";
public float cost;
public String getMessage(){
return message;
}
//每个实现类自己实现
public abstract float getCost();
}
油饼,和糖饼分别实现饼
public class BatterCake extends Cake {
public BatterCake() {
message="batterCake";
}
@Override
public float getCost() {
this.cost=1.2f;
return cost;
}
}
public class OilCake extends Cake{ //饼的实现类,油饼
public OilCake() {
message="oilCake";
}
@Override
public float getCost() {
this.cost=1.5f;
return cost;
}
}
- 可以分别加糖或者加盐,因此先来个装饰器接口
public abstract class CakeDecorator extends Cake {
}
- 分别实现通过装饰器加糖和加盐
/**
* Created by maskwang on 2017/10/15 0015.
* 饼加盐
*/
public class SaltDecorator extends CakeDecorator{
Cake cake;
public SaltDecorator(Cake cake) {
this.cake = cake;
}
@Override
public String getMessage() {
return cake.getMessage()+" with salt ";
}
@Override
public float getCost() {
return cake.getCost()+0.3f;
}
}
public class SugerDecorator extends CakeDecorator {
Cake cake;
public SugerDecorator(Cake cake) {
this.cake = cake;
}
@Override
public String getMessage() {
return cake.getMessage()+" with suger ";
}
@Override
public float getCost() {
return cake.getCost()+0.2f; //饼的钱+糖的钱
}
}
- 测试一下通过装饰器既加糖又加盐
public class Test {
public static void main(String[] args) {
Cake cake = new OilCake();
cake = new SaltDecorator(cake);
cake=new SugerDecorator(cake);
System.out.println(cake.getMessage());
System.out.println(cake.getCost());
}
}
结果如下:
这里解释一下,最后的2.0如何出来,构造出OilCake,cost就是1.5,
cake = new SaltDecorator(cake),那么cost就是1.8。cake=new SugerDecorator(cake),那么就是2.0。
- 我们常见到的IO包下,就运用到装饰者模式,例如BufferedInputStream,DataInputStream等。也可以实现一个装饰器,把字母转化成小写。如下:
package com.designpattern.decoratorpattern;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by maskwang on 2017/10/15 0015.
*/
public class UperCaseInputStream extends FilterInputStream {
public UperCaseInputStream(InputStream in) {
super(in);
}
@Override
public int read() throws IOException {
int c=super.read();
return (c==-1?c:Character.toUpperCase((char)c));
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int result=super.read(b,off,len);
for(int i=off;i<off+result;i++){
b[i]=(byte)Character.toUpperCase((char)b[i]);
}
return result;
}
}
测试IO装饰类
public static void main(String[] args) throws IOException {
// Cake cake = new OilCake();
// cake = new SaltDecorator(cake);
// cake=new SugerDecorator(cake);
// System.out.println(cake.getMessage());
// System.out.println(cake.getCost());
int c;
try {
InputStream in=new UperCaseInputStream(new BufferedInputStream(new FileInputStream("E:\\test.txt")));
while ((c=in.read())>0)
System.out.println((char)(c));
}catch (IOException e){
e.printStackTrace();
}
}
![Uploading image_647020.png . . .]
3. 总结(conclution)
- 从上述我们可以看出来 ,装饰者模式用于已经存在的类添加额外的功能,但是它也有缺点,就是它要在设计中加入大量的小类,会造成额外的空间占用。其核心思想还是如下:
多用组合,少用继承。针对接口编程,不针对实现编程。对拓展开放,对修改关闭。
github地址:github.com/maskwang520