概念
向一个现有的对象添加新的功能,同时又不改变其结构
对现有类的包装,装饰器模式相比生成子类更为灵活
在不增加很多子类的情况下扩展类
设计与实现
设计思想(场景):
奶茶店的波霸奶茶,需要一杯波霸奶茶
材料:珍珠
价格:10元的珍珠奶茶加1份5元的珍珠=15元
10元的珍珠奶茶加2份5元的珍珠=20元
实现
1、提供奶茶接口
package com.xjion.decorator;
//喝奶茶的接口
public interface MilkTea {
//获取奶茶多少钱
int getPrice();
//奶茶使用的材料
String useMaterial();
}
2、将奶茶中的材料抽象出来
package com.xjion.decorator;
/**
* 奶茶使用的材料不知道(根据客户需求)
* 所以将材料单独抽取出来,设计为抽象类,让子类设计具体材料
* 但是需要将材料放入奶茶中才有具体价值,所以需要实现奶茶接口
*/
public abstract class MikeTeaMaterial implements MilkTea {
//将奶茶接口接入进来
public MilkTea milkTea;
public MikeTeaMaterial(MilkTea milkTea) {
super();
this.milkTea = milkTea;
}
@Override
public int getPrice() {//奶茶价格
return milkTea.getPrice();
}
@Override
public String useMaterial() {//奶茶材料
return milkTea.useMaterial();
}
}
3、珍珠奶茶实现奶茶接口
package com.xjion.decorator;
/**
* 提供一个珍珠奶茶,实现奶茶接口
* 材料:珍珠,价格:10
*/
public class PearlMilkTea implements MilkTea {
@Override
public int getPrice() {//价格
return 10;
}
@Override
public String useMaterial() {//核心材料:奶茶
return "珍珠奶茶";
}
}
4、添加珍珠材料
package com.xjion.decorator;
/**
* 珍珠材料装饰类
* 奶茶使用了更多珍珠
* 波霸奶茶
*/
public class Pearl extends MikeTeaMaterial {
public Pearl(MilkTea milkTea) {
super(milkTea);
}
//涨价了:5元
@Override
public int getPrice() {
return super.getPrice()+5;
}
//在珍珠奶茶基础上添加珍珠
@Override
public String useMaterial() {
return super.useMaterial()+"添加:大量珍珠,制作成波霸奶茶!";
}
}
5、购买
package com.xjion.decorator;
public class Buyer {
public static void main(String[] args) {
//制作一杯珍珠奶茶
MilkTea milkTea = new PearlMilkTea();
System.out.println(milkTea.useMaterial()+"--价格:"+milkTea.getPrice());
//添加1份珍珠到奶茶中
// milkTea = new Pearl(milkTea);
// System.out.println(milkTea.useMaterial()+"--价格:"+milkTea.getPrice());
//添加2份珍珠到奶茶中
milkTea = new Pearl(new Pearl(milkTea));
System.out.println(milkTea.useMaterial()+"--价格:"+milkTea.getPrice());
}
}
为了加深印象和理解,这里再写一个很经典的例子,英雄联盟中的学习技能。
设计思想
在英雄联盟中,有个叫提莫的英雄。他是负责瓦罗兰大陆的班德尔城安全的侦察兵首领,我们知道英雄升级以后系统会赋予新的技能点供英雄去学习
实现
1、提供英雄接口
package com.lol.decorator;
//提供英雄接口
public interface Hero {
//学习技能
void learnSkill();
}
2、抽象英雄技能
package com.lol.decorator;
//英雄的技能(抽象的技能QWER具体继承即可)
public abstract class HeroSkill implements Hero {
//把英雄接口接出来
public Hero hero;
public HeroSkill(Hero hero) {
this.hero = hero;
}
@Override
public void learnSkill() {//学习技能
hero.learnSkill();
}
}
3、生成英雄提莫
package com.lol.decorator;
//生成英雄提莫
public class Timor implements Hero {
private String name;
public Timor(String name) {
this.name = name;
}
@Override
public void learnSkill() {
System.out.println(name+"学习技能完成!!!");
}
}
4、提供技能装饰器
package com.lol.decorator;
public class Skill extends HeroSkill {
private String key;
private String skillName;
public Skill(Hero hero, String key, String skillName) {
super(hero);
this.key = key;
this.skillName = skillName;
}
@Override
public void learnSkill() {
System.out.println("学习了技能"+key+":"+skillName);
super.learnSkill();
}
}
5、学习技能
package com.lol.decorator;
public class Learn {
public static void main(String[] args) {
Hero hero = new Timor("提莫");
//第一种实现方式
// HeroSkill heroSkill = new Skill(
// new Skill(
// new Skill(
// new Skill(hero, "R", "种蘑菇"),
// "E", "小莫快跑"),
// "W", "毒性射击"),
// "Q", "致盲吹箭");
// heroSkill.learnSkill();
//第二种实现方式
HeroSkill heroSkill = new Skill(hero, "R", "种蘑菇");
heroSkill = new Skill(heroSkill, "E", "小莫快跑");
heroSkill = new Skill(heroSkill, "W", "毒性射击");
heroSkill = new Skill(heroSkill, "Q", "致盲吹箭");
heroSkill.learnSkill();
}
}
特点
装饰器模式是继承的一种替代模式
可以动态扩展一个实现类的功能,也可以动态增加和删除功能
多层装饰使用时会相对比较复杂,但减少了子承父的耦合性