装饰者模式
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
首先来分析一下为什么使用装饰者模式。例如,让一个对象添加一个新的功能,我们第一想到的就是创建一个类来继承这个类,然后添加新的功能方法。这种方式在大部分简单的场景中是可取的,可是也有一些复杂的情况。例如,各种功能之间要相互组合使用,拿手抓饼来说吧,一个手抓饼里面可以加各种食材,比如加个烤肠,加个鸡蛋等等,我以前上班的时候路过地铁站都会买一个手抓饼当早餐,既美味,又方便。平时的时候我加一个鸡蛋,一份青菜,当我发工资的时候我就阔绰一把,加一个鸡蛋,一份青菜,再加一个烤肠。可见手抓饼里的东西是可以随意组合的,假如说我们用继承的方式,我想加一个鸡蛋和一份青菜,那么我就要创建一个子类来继承手抓饼,在子类中组合鸡蛋和青菜。如果我想加一个鸡蛋一份青菜和一根烤肠,那么我就要再创建一个子类来继承手抓饼,在子类中组合鸡蛋青菜和烤肠。当然,可能月底了,没钱了,我只加一个鸡蛋,那么就又多了一种组合方式,可见,这种组合方式是特别多的,如果使用继承,那么子类将会多到爆炸。过些时候老板又推出了新的食品,可以加里脊肉了,那么多一种食品,它们的组合方式将会成几何的方式增长,显然这种场景下,使用继承的方式是不可取的,那么这个时候就可以使用装饰者模式了。
装饰模式的使用场景:
装饰模式的优点:
示例代码:
抽象手抓饼接口:
/**
* 手抓饼抽象
*/
public interface HandPancake {
String description(); //描述
float price(); //价格
}
创建手抓饼实例:
public class Pancake implements HandPancake{
private String description="煎饼";
private float price =4;
@Override
public String description() {
return description;
}
@Override
public float price() {
return price;
}
}
抽象手抓饼组合的食材基类:
public abstract class Decorator implements HandPancake{
protected HandPancake handPancake;
public Decorator(HandPancake handPancake){
this.handPancake=handPancake;
}
}
创建鸡蛋食材实例:
public class Egg extends Decorator {
private String description="鸡蛋";
private float price =1;
public Egg(HandPancake handPancake){
super(handPancake);
}
@Override
public String description() {
return handPancake.description()+"+"+description;
}
@Override
public float price() {
return handPancake.price()+price;
}
}
创建青菜食材实例:
public class Greens extends Decorator {
private String description="青菜";
private float price =0.5f;
public Greens(HandPancake handPancake) {
super(handPancake);
}
@Override
public String description() {
return handPancake.description() + "+" + description;
}
@Override
public float price() {
return handPancake.price() + price;
}
}
创建热狗食材实例:
public class HotDog extends Decorator {
private String description="热狗";
private float price =2;
public HotDog(HandPancake handPancake) {
super(handPancake);
}
@Override
public String description() {
return handPancake.description() + "+" + description;
}
@Override
public float price() {
return handPancake.price() + price;
}
}
现在可以自由搭配买手抓饼了
/**
* 手抓饼4元
* 加鸡蛋1元
* 加热狗2元
* 加青菜0.5元
* 上海手抓饼好贵啊,现在我都不吃了
*/
public class Test {
public static void main(String[] args) {
HandPancake pancake = new Pancake(); //一份手抓饼
pancake = new Egg(pancake); //加个鸡蛋
pancake = new Greens(pancake); //加点青菜
System.out.println("你买的是:" + pancake.description() + "\t总计:" + pancake.price() + "元");
pancake = new HotDog(pancake); //再加根烤肠吧
System.out.println("你买的是:" + pancake.description() + "\t总计:" + pancake.price() + "元");
}
}
运行结果:
可以看到,使用装饰者模式,各个食材之间可以随意组合,并没有出现类的爆炸性增长。在java中,装饰者模式使用最经典的就是IO流了,大家可以去操作一下IO流,体会一下装饰者模式的特点。