• 设计模式 - 结构型模式考点篇:装饰者模式(概念 | 案例实现 | 优缺点 | 使用场景)


    目录

    一、结构型模式

    1.1、装饰者模式

    1.1.1、概念

    1.1.2、案例实现

    1.1.3、优缺点

    1.1.4、使用场景


    一、结构型模式


    1.1、装饰者模式

    1.1.1、概念

    装饰者模式就是指在不改变现有对象结构的情况下,动态的给该对象增加一些职责(增加额外功能)的模式.

    例如,现在要开发一个点餐系统,有一个抽象类快餐类,快餐店里有炒面、炒饭,分别去继承实现.  如果现在需要添加额外的配料(比如 鸡蛋),那么计算额外加钱就会不叫麻烦,就需要分别给 炒面类 和 炒饭类 定义一个子类(鸡蛋炒面类、鸡蛋炒饭类).  再者,如果要新增一个快餐类(比如 凉皮),就需要定义更多的子类.  通过装饰者模式就可以在不需要添加子类的情况下,动态的添加配料.

    装饰者模式中的角色如下:

    • 抽象构件角色:定义一个抽象接口用来规范附加的对象(比如上述的 快餐类).
    • 具体构件角色:实现抽象构件,将来会被添加一些职责(比如上述的 炒面类 和 炒饭类).
    • 抽象装饰角色:继承抽象构件 和 持有抽象构件的引用,可以通过 子类 扩展具体的构件.
    • 具体装饰角色:继承抽象装饰,重写相关方法,给具体的构件对象添加附加责任.

    1.1.2、案例实现

    实现上述案例.

    1. /**
    2. * 抽象构建角色: 快餐
    3. */
    4. public abstract class FastFood {
    5. private float price; //价格
    6. private String desc; //描述
    7. public abstract float cost(); //获取最终价格
    8. public FastFood() {
    9. }
    10. public FastFood(float price, String desc) {
    11. this.price = price;
    12. this.desc = desc;
    13. }
    14. public float getPrice() {
    15. return price;
    16. }
    17. public void setPrice(float price) {
    18. this.price = price;
    19. }
    20. public String getDesc() {
    21. return desc;
    22. }
    23. public void setDesc(String desc) {
    24. this.desc = desc;
    25. }
    26. }
    1. /**
    2. * 具体构建角色: 炒饭类
    3. */
    4. public class Rice extends FastFood{
    5. public Rice() {
    6. super(10, "炒饭");
    7. }
    8. @Override
    9. public float cost() {
    10. return getPrice();
    11. }
    12. }
    1. /**
    2. * 具体构建角色: 面条类
    3. */
    4. public class Noodles extends FastFood {
    5. public Noodles() {
    6. super(12, "炒面");
    7. }
    8. @Override
    9. public float cost() {
    10. return getPrice();
    11. }
    12. }
    1. /**
    2. * 抽象装饰角色: 配料类
    3. */
    4. public abstract class Garnish extends FastFood {
    5. private FastFood fastFood;
    6. public FastFood getFastFood() {
    7. return fastFood;
    8. }
    9. public void setFastFood(FastFood fastFood) {
    10. this.fastFood = fastFood;
    11. }
    12. public Garnish(FastFood fastFood, float price, String desc) {
    13. super(price, desc);
    14. this.fastFood = fastFood;
    15. }
    16. }
    1. /**
    2. * 抽象装饰角色: 配料类
    3. */
    4. public abstract class Garnish extends FastFood {
    5. private FastFood fastFood;
    6. public FastFood getFastFood() {
    7. return fastFood;
    8. }
    9. public void setFastFood(FastFood fastFood) {
    10. this.fastFood = fastFood;
    11. }
    12. public Garnish(FastFood fastFood, float price, String desc) {
    13. super(price, desc);
    14. this.fastFood = fastFood;
    15. }
    16. }
    1. /**
    2. * 具体装饰角色: 鸡蛋配料
    3. */
    4. public class Egg extends Garnish{
    5. public Egg(FastFood fastFood) {
    6. super(fastFood, 1, "鸡蛋");
    7. }
    8. @Override
    9. public float cost() {
    10. return getPrice() + getFastFood().cost();
    11. }
    12. @Override
    13. public String getDesc() {
    14. return super.getDesc() + getFastFood().getDesc();
    15. }
    16. }
    1. /**
    2. * 具体装饰角色: 培根配料
    3. */
    4. public class Bacon extends Garnish{
    5. public Bacon(FastFood fastFood) {
    6. super(fastFood, 2, "培根");
    7. }
    8. @Override
    9. public float cost() {
    10. return getPrice() + getFastFood().cost();
    11. }
    12. @Override
    13. public String getDesc() {
    14. return super.getDesc() + getFastFood().getDesc();
    15. }
    16. }
    1. public class Client {
    2. public static void main(String[] args) {
    3. //1.带你一份炒饭
    4. FastFood food = new Rice();
    5. System.out.println(food.getDesc() + " " + food.cost() + "元");
    6. System.out.println("================");
    7. //2.加一份鸡蛋
    8. food = new Egg(food);
    9. System.out.println(food.getDesc() + " " + food.cost() + "元");
    10. System.out.println("================");
    11. //3.加一份鸡蛋
    12. food = new Egg(food);
    13. System.out.println(food.getDesc() + " " + food.cost() + "元");
    14. System.out.println("================");
    15. //4.加一个培根
    16. food = new Bacon(food);
    17. System.out.println(food.getDesc() + " " + food.cost() + "元");
    18. }
    19. }

    执行结果如下:

    1.1.3、优缺点

    优点:

    动态扩展:比继承具有更好的扩展性(继承时静态附加责任,装饰者时动态添加责任),可以在不修改原类的情况下,给对象添加责任.

    缺点:

    增加系统复杂度:装饰者比继承使用的类可能会少,但比继承使用的对象可能更多,更多的对象在程序排查错误的时候可能更复杂.

    1.1.4、使用场景

    1. 当不能采用继承的方式对程序进行扩展,比如存在大量的独立扩展,为了支持每一种组合产生大量子类(例如上述栗子中的给 炒饭加鸡蛋,导致出现 鸡蛋炒饭类),导致子类数目爆炸增长、或者是 类定位为 final 类型(不能继承).

    2. 在不影响其他类的情况下,以动态的方式添加责任.

  • 相关阅读:
    软件系统测试和验收测试有什么联系与区别?专业软件测试方案推荐
    2022年6月编程语言排行,第一名居然是它?!
    音频怎么录制?让你轻松成为录音专家!
    MPLS-LDP(个人学习笔记)
    国家开放大学 训练题
    uView u-slider 自定义滑块
    SpringBoot 如何实现文件上传和下载
    Java 获取类中所有字段 转换为 json字符串 Java 类中字段转换为json字符串 javabean 字段 转换为 jsonStr
    计算机网络安全技术与应用
    金仓数据库KingbaseES客户端编程开发框架-MyBatis(2. 概述 3. MyBatis配置说明)
  • 原文地址:https://blog.csdn.net/CYK_byte/article/details/133706296