装饰器模式

mac2025-04-20  5

概念

向一个现有的对象添加新的功能,同时又不改变其结构

对现有类的包装,装饰器模式相比生成子类更为灵活

在不增加很多子类的情况下扩展类

设计与实现

设计思想(场景):

奶茶店的波霸奶茶,需要一杯波霸奶茶

材料:珍珠

价格: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(); } }

特点

装饰器模式是继承的一种替代模式

可以动态扩展一个实现类的功能,也可以动态增加和删除功能

多层装饰使用时会相对比较复杂,但减少了子承父的耦合性

最新回复(0)