目录
装饰者模式又叫装饰器模式
用途:在不改变现有对象的结构情况下,动态给一个对象增加额外的功能。
1 适用场景
比如换装游戏,就可以使用到装饰者模式。先有一个小人,在不改变小人的情况下,动态给小人增加各种衣服就是装饰者模式。
再比如煎饼果子有基础版,还可以放各种配料,也可以使用到装饰者模式。
煎饼果子就是一个对象,在不改变煎饼果子的情况下,动态给煎饼果子添加额外的配料(玉米沙拉、鸡柳、辣条、香肠……)
2 代码实现
下面使用装饰者模式实现一下计算煎饼果子加各种配料的价格的功能。
先有一个对象接口“小吃”,可以给这给对象接口添加职责(计算多少钱)
package com.qing.decorator;
public interface IXiaochi {
int howMuch();
}
然后我们写一个煎饼果子对象。煎饼果子基础版(没有加额外的配料)
package com.qing.decorator;
public class Jianbingguozi implements IXiaochi {
//煎饼果子基础版6块
@Override
public int howMuch() {
return 6;
}
}
写一个装饰抽象类,实现了对象接口“小吃”,该装饰抽象类可以从外类来扩展“小吃”
package com.qing.decorator;
//抽象装饰角色:配料
public abstract class Peiliao implements IXiaochi {
}
下面是具体的装饰对象,给“小吃”添加加配料重新计算价格的职责。
该装饰对象继承装饰抽象类(配料),构造方法里添加参数“小吃”,加沙拉,额外收费两元,价格叠加。
package com.qing.decorator;
public class Salad extends Peiliao {
//加沙拉另外收费2块
private static final int price=2;
private IXiaochi xiaochi;
public Salad(IXiaochi xiaochi) {
this.xiaochi = xiaochi;
}
@Override
public int howMuch() {
System.out.println("加一份沙拉,多"+price+"块");
return xiaochi.howMuch()+this.price;
}
}
加鸡柳
package com.qing.decorator;
public class Jiliu extends Peiliao {
//加鸡柳另外收费3块
private static final int price=3;
private IXiaochi xiaochi;
public Jiliu(IXiaochi xiaochi) {
this.xiaochi = xiaochi;
}
@Override
public int howMuch() {
System.out.println("加一份鸡柳,多"+price+"块");
return xiaochi.howMuch()+this.price;
}
}
加辣条
package com.qing.decorator;
public class Latiao extends Peiliao{
//加辣条另外收费1块
private static final int price=1;
private IXiaochi xiaochi;
public Latiao(IXiaochi xiaochi) {
this.xiaochi = xiaochi;
}
@Override
public int howMuch() {
System.out.println("加一份辣条,多"+price+"块");
return xiaochi.howMuch()+this.price;
}
}
想加啥就加啥
测试类(像俄罗斯套娃一样,配料实例化的时候,参数使用的是上一个版本“小吃”的价格,重新计算价格的时候会使用上一个版本“小吃”的价格加上一份配料单独的价格)
@Test
void test1() {
//基础版煎饼果子
Jianbingguozi jianbingguozi = new Jianbingguozi();
System.out.println("煎饼果子基础版:"+jianbingguozi.howMuch()+"块");
//加一份鸡柳
Jiliu plusJiliu = new Jiliu(jianbingguozi);
//加一份玉米沙拉
Salad plusSalad = new Salad(plusJiliu);
//再加一份玉米沙拉
Salad plusSalad2 = new Salad(plusSalad);
//加一份辣条
Latiao pluslatiao = new Latiao(plusSalad2);
System.out.println("总共需要支付"+pluslatiao.howMuch()+"块");
}
结果
3 功能扩展
现在这个摊位推出了烤冷面小吃,也要加配料计算价格。
再搞一个烤冷面基础版的对象。
package com.qing.decorator;
public class Kaolengmian implements IXiaochi{
//烤冷面基础版5块
@Override
public int howMuch() {
return 5;
}
}
烤冷面还可以额外加金针菇,再添加一个装饰对象(金针菇)
package com.qing.decorator;
public class Jinzhengu extends Peiliao {
//加金针菇另外收费2块
private static final int price=2;
private IXiaochi xiaochi;
public Jinzhengu(IXiaochi xiaochi) {
this.xiaochi = xiaochi;
}
@Override
public int howMuch() {
System.out.println("加一份金针菇,多"+price+"块");
return xiaochi.howMuch()+this.price;
}
}
测试
@Test
void test1() {
//基础版烤冷面
Kaolengmian kaolengmian = new Kaolengmian();
System.out.println("烤冷面基础版:" + kaolengmian.howMuch() + "块");
//加一份玉米沙拉
Salad plusSalad = new Salad(kaolengmian);
//加一份金针菇
Jinzhengu plusjinzhengu = new Jinzhengu(plusSalad);
System.out.println("总共需要支付" + plusjinzhengu.howMuch() + "块");
}
结果
可以看到装饰者模式,在不改变现有对象的结构情况下,很容易地动态给对象增加了额外的功能。完全遵守了开闭原则(对于扩展是开放的,对于更改是封闭的。)
装饰者模式主要优点:
1 是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用。
2 通过使用各装饰类的排列组合,可以实现不同效果
3 装饰者模式完全遵守开闭原则。
装饰者的本质是一个套娃。