设计模式之装饰器模式
装饰器模式是一种结构型设计模式,可以做到在不改变原来对象功能的情况下,向原有的对象添加新的功能,起到一个装饰的作用。具体的做法是创建一个装饰器类,用来包装原有的类,在不改变原有类方法的情况下,为原有类添加新的功能。
来看一个例子,我们在外面吃饭,有很多食物,其中有烧烤和火锅。比如我们点了烧烤,但是觉得味道不够爽,所以我们选择让老板加盐,或者加辣椒,这里的加盐和加辣椒其实就是对事物起装饰作用。用代码实现如下:
创建Food接口
提供两个抽象方法
public interface Food {
/**
* 返回描述
* @return
*/
String getDesc();
/**
* 返回价格
* @return
*/
String getCost();
}
创建实现接口的实现类
Barbecue实现类
public class BarbecueFood implements Food {
/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
return "烧烤";
}
/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
Double cost = 3.0;
return String.format("最后价格:%s块", cost);
}
}
Hotpot实现类
public class HotpotFood implements Food {
/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
return "火锅";
}
/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
Double cost = 100.0;
return String.format("最后价格:%s块", cost);
}
}
创建装饰器基类
FoodDecorator是一个抽象类,其中组合Food类
public abstract class FoodDecorator implements Food {
protected Food food;
public FoodDecorator(Food food) {
this.food = food;
}
/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
return food.getDesc();
}
/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
return food.getCost();
}
}
创建SaltFoodDecorator装饰器类
public class SaltFoodDecorator extends FoodDecorator {
public SaltFoodDecorator(Food food) {
super(food);
}
/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
String result = "加盐的" + food.getDesc();
return result;
}
/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
Double salt = 2.0;
System.out.println(String.format("加盐多收%s块", salt));
String result = food.getCost() + " + " + salt + "块";
return result;
}
}
创建PepperFoodDecorator装饰器类
public class PepperFoodDecorator extends FoodDecorator {
public PepperFoodDecorator(Food food) {
super(food);
}
/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
String result = "加盐的" + food.getDesc();
return result;
}
/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
Double pepper = 10.0;
System.out.println(String.format("加辣椒多收%s块", pepper));
String result = food.getCost() + " + " + pepper + "块";
return result;
}
}
最后来测试一下
public class Main {
public static void main(String[] args) {
//创建不用装饰器修饰的Food
Food food = new BarbecueFood();
display(food.getDesc());
display(food.getCost());
System.out.println("-------------分割线---------------");
//创建用SaltFoodDecorator装饰的Food
Food barbecue = new SaltFoodDecorator(new BarbecueFood());
display(barbecue.getDesc());
display(barbecue.getCost());
System.out.println("-------------分割线---------------");
//创建用PepperFoodDecorator装饰的Food
Food hotSpot = new PepperFoodDecorator(new HotpotFood());
display(hotSpot.getDesc());
display(hotSpot.getCost());
}
private static void display(Object obj) {
System.out.println(obj);
}
}
结果如下:
烧烤
最后价格:3.0块
-------------分割线---------------
加盐的烧烤
加盐多收2.0块
最后价格:3.0块 + 2.0块
-------------分割线---------------
加盐的火锅
加辣椒多收10.0块
最后价格:100.0块 + 10.0块
来看一下类图会更加地清晰
END
装饰器模式在日常开发中也有很多应用,典型的就是JDK里面的IO。
InputStream代表输入流,输入来源可以是文件(FileInputStream)、管道(PipedInputStream)、数组(ByteArrayInputStream)等。就像上面的烧烤,火锅。FilterInputStream就是装饰器的基类,他的实现类是一系列的装饰器,比如BufferedInputStream可以用缓冲区来修饰InputStream,把InputSteam包装成有缓冲区的输入流。