来源:
https://zhuanlan.zhihu.com/p/64584677
我们有一个原味咖啡,有顾客要原味,有顾客要加奶,有顾客要先加奶在加糖,有顾客要先加糖在加奶。
这个问题首先不变的就是原味咖啡,其他的都是在原味咖啡上进行添加。
public interface ICoffee { void makeCoffee(); } public class OriginalCoffee implements ICoffee { @Override public void makeCoffee() { System.out.print("原味咖啡 "); } } public abstract class CoffeeDecorator implements ICoffee { private ICoffee coffee; public CoffeeDecorator(ICoffee coffee){ this.coffee=coffee; } @Override public void makeCoffee() { coffee.makeCoffee(); } } public class MilkDecorator extends CoffeeDecorator { public MilkDecorator(ICoffee coffee) { super(coffee); } @Override public void makeCoffee() { super.makeCoffee(); addMilk(); } private void addMilk(){ System.out.print("加奶 "); } } public class SugarDecorator extends CoffeeDecorator { public SugarDecorator(ICoffee coffee) { super(coffee); } @Override public void makeCoffee() { super.makeCoffee(); addSugar(); } private void addSugar(){ System.out.print("加糖"); } } public static void main(String[] args) { //原味咖啡 ICoffee coffee=new OriginalCoffee(); coffee.makeCoffee(); System.out.println(""); //加奶的咖啡 ICoffee coffee1 = new MilkDecorator(coffee); coffee1.makeCoffee(); System.out.println(""); //先加奶后加糖的咖啡 ICoffee coffee2 =new SugarDecorator(coffee1); coffee2.makeCoffee(); } // 输出 原味咖啡 原味咖啡 加奶 原味咖啡 加奶 加糖
public abstract class Pancake { String description = "普通煎饼"; public String getDescription(){ return description; } public abstract double cost(); } // 定义具体的被装饰者,这里是煎饼果子,当然还可以有鸡蛋灌饼、手抓饼等其他被装饰者 public class Battercake extends Pancake { @Override public double cost() { return 8; } public Battercake(){ description = "煎饼果子"; } } // 抽象的装饰器对象,定义一个调料抽象类 public abstract class CondimentDecorator extends Pancake { // 持有组件对象 protected Pancake pancake; public CondimentDecorator(Pancake pancake){ this.pancake = pancake; } public abstract String getDescription(); } // 具体的装饰者,我们定义一个鸡蛋装饰器,一个火腿装饰器 public class Egg extends CondimentDecorator { public Egg(Pancake pancake){ super(pancake); } @Override public String getDescription() { return pancake.getDescription() + "加鸡蛋"; } @Override public double cost() { return pancake.cost() + 1; } } public class Sausage extends CondimentDecorator{ public Sausage(Pancake pancake){ super(pancake); } @Override public String getDescription() { return pancake.getDescription() + "加火腿"; } @Override public double cost() { return pancake.cost() + 2; } } public static void main(String[] args) { //买一个普通的煎饼果子 Pancake battercake = new Battercake(); System.out.println(battercake.getDescription() + "花费:"+battercake.cost() + "元"); //买一个加双蛋的煎饼果子 Pancake doubleEgg = new Battercake(); doubleEgg = new Egg(doubleEgg); doubleEgg = new Egg(doubleEgg); System.out.println(doubleEgg.getDescription() + "花费" + doubleEgg.cost() + "元"); //加火腿和鸡蛋 Pancake battercakePlus = new Battercake(); battercakePlus = new Egg(battercakePlus); battercakePlus = new Sausage(battercakePlus); System.out.println(battercakePlus.getDescription() + "花费" + battercakePlus.cost() + "元"); } 煎饼果子花费:8.0元 煎饼果子加鸡蛋加鸡蛋花费10.0元 煎饼果子加鸡蛋加火腿花费11.0元
Component:抽象组件,装饰者和被装饰者共同的父类,是一个接口或者抽象类,用来定义基本行为
ConcreteComponent:具体的组件对象,实现类 ,即被装饰者,通常就是被装饰器装饰的原始对象
Decorator:所有装饰器的抽象父类,一般是抽象类,实现接口;它的属性必然有个指向
ConcreteDecorator:具体的装饰对象,实现具体要被装饰对象添加的功能。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
装饰模式的本质:动态组合而不是全部穷举
装饰对象动态的对被装饰者进行装饰。
优缺点
装饰模式的优点:
装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”
装饰模式的缺点:
使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
Copyright © 2023 leiyu.cn. All Rights Reserved. 磊宇云计算 版权所有 许可证编号:B1-20233142/B2-20230630 山东磊宇云计算有限公司 鲁ICP备2020045424号
磊宇云计算致力于以最 “绿色节能” 的方式,让每一位上云的客户成为全球绿色节能和降低碳排放的贡献者