程序员理解设计模式(程序员必备技能)
相信通过名称大家可以大致猜出“装饰者模式”的含义,它的核心思想就是通过一些“装饰品(类)”对原有的基础类进行包装,从而增强或者是完成某些特定的功能。
“装饰者模式”可以动态地将新功能附加到对象上。并且在对象的扩展方面,使用该模式要比单纯的通过继承更加有弹性。
核心设计UML类图:
通过上面的UML类图,可以得知装饰者模式大致可以分为四个角色:
Component(抽象组件): 可以是一个抽象类或者接口,是要被包装类的顶级类。
ConcreteComponent(具体组件): Component的子类,是具体被包装的类。
注:有的时候会存在很多ConcreteComponent类,为了方便统一管理我们可以根据不同ConcreteComponent的特性在抽象出不同父类,将其放置在上图Component和ConcreteComponent之间,也就是在这两者之间设计一个缓冲层。
Decorator(装饰者): 该类继承或实现Component,并在类中聚合一个Component类的对象。
ConcreteDecorator(具体装饰者): Decorator的子类,是具体的装饰者类,该类的作用就是装饰ConcreteComponent类。
简单案例通过上面的类图和文字描述相信大家对“装饰者模式”应该有了一些基本的认识,下面让我们通过一个小案例来加深对该设计模式的理解。
案例:有一个饮品店,该店有不同口味的饮品和不同种类的配料。现在需要一个下单系统,要求该系统可以计算出客户通过自由搭配而得的饮品价格。
饮料 => Component(抽象组件)
public abstract class Drink { // 描述 private String describe; // 价格 private double price = 0.0; // 计算费用的抽象方法 public abstract double cost(); // get()和set() }
奶茶 => ConcreteComponent(具体组件)
public class TeaWithMilk extends Drink { public TeaWithMilk() { setDescribe("奶茶"); setPrice(6.0); } @Override public double cost() { // 当前奶茶的价格 return getPrice(); } }
调味品 => Decorator(装饰者)
public class Seasoning extends Drink { // 聚合一个Drink对象,也就是被装饰的对象。 private Drink drink; // 构造 public Seasoning(Drink drink) { this.drink = drink; } @Override public double cost() { // 当前调味品的价格加上被装饰对象的价格。 return getPrice() drink.cost(); } /** * 重写getDescribe方法,方便输出打印 */ @Override public String getDescribe() { return super.getDescribe() " " getPrice() " " drink.getDescribe(); } }
ConcreteDecorator(具体装饰者)
/** * 珍珠 */ public class Pearl extends Seasoning { // 构造 public Pearl(Drink drink) { super(drink); setDescribe("珍珠"); setPrice(2.5); } } /** * 燕麦 */ public class Oats extends Seasoning { // 构造方法 public Oats(Drink drink) { super(drink); setDescribe("燕麦"); setPrice(1.0); } }
客户端测试类
public class Client { // 订单:一杯奶茶 一份燕麦 一份珍珠 public static void main(String[] args) { // 一杯奶茶 Drink drink = new TeaWithMilk(); System.out.println("需支付:"); System.out.println(drink.getDescribe() drink.cost()); // 加一份燕麦 drink = new Oats(drink); System.out.println("加一份燕麦需支付:"); System.out.println(drink.getDescribe() " 总共:" drink.cost()); drink = new Pearl(drink); System.out.println("再加一份珍珠需支付:"); System.out.println(drink.getDescribe() " 总共:" drink.cost()); } }
执行结果:
以上就是该案例的所有代码,可能一开始看这个代码的时候不是特别理解。不要慌,容我给大家稍加讲解,相信各位就能一目了然,明白其中的奥秘。
其实该案例运用了递归算法的思想,我们可以拆解一下。
第一步:客户下单,要了一份奶茶。第二步:客户在奶茶的基础上,点了一个燕麦。此时我们需要装饰一下第一步中的奶茶(将其视为一个整体),从而得到一个加了燕麦的奶茶。第三步:客户在加了燕麦的奶茶基础上,点了一个珍珠。此时我们需要装饰的就是第二步中加了燕麦的奶茶了(将其视为一个整体)。自此整个订单完成,得到一个加了燕麦和珍珠的奶茶(装饰完成)。
示例图:
这样解释是不是就清楚地明白其中的奥秘了。
总结1、使用装饰者模式可以更加灵活的对程序进行扩展,可随着业务的需要动态的新增功能,也可在不需要时进行撤回,并且通过不同的装饰者和被装饰者可以衍生出不同的组合。
2、使用装饰者模式对程序进行扩展是符合ocp原则的。
3、使用装饰者模式也会增加代码的复杂性,并且当使用过度时会衍生出过多小的类,从而增加系统的维护成本。
任何设计模式都是有其优点和缺点的,我们要做到在合适的场景合理的使用设计模式。
今天的分享就到这里了,如果感觉“菜鸟”写的文章还不错,记得点赞加关注呦!你们的支持就是我坚持下去的动力。文章哪里写的有问题的也希望大家可以指出,我会虚心受教。
,
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com