前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java设计模式-装饰器模式 理论代码相结合

Java设计模式-装饰器模式 理论代码相结合

作者头像
宁在春
发布2022-10-31 15:14:35
3750
发布2022-10-31 15:14:35
举报
文章被收录于专栏:关于Java学习@宁在春

继Java设计模式适配器模式后的装饰器模式来啦,让我们一起看看吧。 会了就当复习丫,不会来一起来看看吧。 很喜欢一句话:“八小时内谋生活,八小时外谋发展”。 如果你也喜欢,让我们一起坚持吧!! 共勉😁

在这里插入图片描述
在这里插入图片描述

一张旧图,恍惚间念起旧人

Java设计模式-装饰器模式

一、装饰器模式介绍

1)引入:

上班族大多都有睡懒觉的习惯,每天早上上班时间都很紧张,于是很多人为了多睡一会,就会用方便的方式解决早餐问题。有些人早餐可能会吃煎饼,煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么“加码”,都还是一个煎饼。在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等,都是装饰器模式。在我们自己行业就是这个东西得加需求啦

在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰器模式来实现。

2)概述

装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式

3)角色结构

  1. 抽象构件(Component):定义一个抽象接口以规范准备接收附加责任的对象。
  2. 具体构件(ConcreteComponent):实现抽象构件,通过装饰角色为其添加一些职责。
  3. 抽象装饰(Decorator):继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  4. 具体装饰(ConcreteDecorator):实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

4)使用场景

1、扩展一个类的功能。

2、动态增加功能,动态撤销。

就是主要为了方便扩展。

5)举个例子

快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦。

在这里插入图片描述
在这里插入图片描述

这是一个快餐店的例子,这么咋一看,感觉还可以,但是如果不再局限于炒饭FriedRice和炒面FriedNoodies中,想要做一些扩展,例如加一个炒粉Fried sweet potato powder,就又要额外增加一个整体,再往下重复实现鸡蛋、培根等等的类。增加这么多,就会造成类爆炸,特别多,就非常不合适。

会产生过多的子类。欲知后事如何,请看下文👇。

二、装饰器模式实现

2.1、前言

接下来,我们用装饰器的模式来重构一下代码,看看会产生哪些方面的变化哈。也来一起看看装饰器模式的精髓。

不过图也要改变一下啦,变成这样子的啦:

在这里插入图片描述
在这里插入图片描述

我们先来讲讲这张图和上一张图的区别。

  1. 炒饭炒面FriedRice和FriedNoodies还是继承FastFoot
  2. 之前的配料Egg和Bacon不再位于 炒饭炒面下面,而是继承于抽象的配料类下,而配料类Garnish又继承于FastFoot

这么看好像还是少了点东西,结合代码我们一起来看一看。

我们把角色定位一下:

  1. 抽象构件(Component):FastFoot类 即快餐类
  2. 具体构件(ConcreteComponent): FriedRice和FriedNoodies 即炒饭炒面
  3. 抽象装饰(Decorator):Garnish 类
  4. 具体装饰(ConcreteDecorator) Egg和Bacon 类,即鸡蛋和培根为具体装饰类

2.2、代码实现

👇下面看代码一步一步实现看一下:

FastFoot快餐接口:即抽象构件

代码语言:javascript
复制
//快餐接口
public abstract class FastFood {
    private float price;
    private String desc;

    public FastFood() {  }

    public FastFood(float price, String desc) {
        this.price = price;
        this.desc = desc;
    }

    //set、get 方法
    public void setPrice(float price) {  this.price = price; }

    public float getPrice() { return price; }

    public String getDesc() { return desc;  }

    public void setDesc(String desc) {    this.desc = desc;  }

    public abstract float cost();  //获取价格
}

FriedRice和FriedNoodies 即炒饭炒面 即具体构件

代码语言:javascript
复制
//炒饭
public class FriedRice extends FastFood {

    public FriedRice() {
        super(10, "炒饭");
    }
	// 获取价格
    public float cost() {
        return getPrice();
    }
}

//炒面
public class FriedNoodles extends FastFood {

    public FriedNoodles() {
        super(12, "炒面");
    }
	// 获取价格
    public float cost() {
        return getPrice();
    }
}

Garnish 即配料类 抽象装饰

代码语言:javascript
复制
public abstract class Garnish extends FastFood {

    private FastFood fastFood;

    public FastFood getFastFood() {   return fastFood; }

    public void setFastFood(FastFood fastFood) {  this.fastFood = fastFood; }

    public Garnish(FastFood fastFood, float price, String desc) {
        super(price,desc);
        this.fastFood = fastFood;
    }
}

Egg和Bacon类,即鸡蛋和培根为 具体装饰类

代码语言:javascript
复制
//鸡蛋配料
public class Egg extends Garnish {

    public Egg(FastFood fastFood) {  super(fastFood,1,"鸡蛋");  }

    // 这里是返回了 炒饭加 鸡蛋的钱的
    public float cost() {  return getPrice() + getFastFood().getPrice();  }

    @Override
    public String getDesc() {  return super.getDesc() + getFastFood().getDesc(); }
}

//培根配料
public class Bacon extends Garnish {

    public Bacon(FastFood fastFood) {  super(fastFood,2,"培根"); }

    @Override
    public float cost() {  return getPrice() + getFastFood().getPrice(); }

    @Override
    public String getDesc() {  return super.getDesc() + getFastFood().getDesc();  }
}

测试类:

代码语言:javascript
复制
public class Client {
    public static void main(String[] args) {
        //点一份炒饭
        FastFood food = new FriedRice();
        //花费的价格
        System.out.println(food.getDesc() + " " + food.cost() + "元");

        System.out.println("========");
        //点一份加鸡蛋的炒饭
        FastFood food1 = new FriedRice();

        food1 = new Egg(food1);
        //花费的价格
        System.out.println(food1.getDesc() + " " + food1.cost() + "元");

        System.out.println("========");
        //点一份加培根的炒面
        FastFood food2 = new FriedNoodles();
        food2 = new Bacon(food2);
        //花费的价格
        System.out.println(food2.getDesc() + " " + food2.cost() + "元");
    }
}

这就解决了我们刚开始的一个问题,如果还需要进行扩张,需要增加一个炒河粉 那么只需要写一个炒河粉的类来继承FastFoot快餐类即可,如需增加配料,也只要写个配料类来继承Garnish配料类即可。其他代码均不用改变,完全符合开闭原则。也比原本减少了类的产生。😁

三、总结

1、使用场景

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。 不能采用继承的情况主要有两类:
    • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类定义不能继承(如final类)

    在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

2、优点:

  1. 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
  2. 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
  3. 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
  4. 装饰器模式完全遵守开闭原则

3、缺点:

  • 装饰器模式会增加许多子类,过度使用会增加程序得复杂性。多层装饰比较复杂。

四、自言自语

你卷我卷,大家卷,什么时候这条路才是个头啊。😇(还是直接上天吧)

有时候也想停下来歇一歇,一直做一个事情,感觉挺难坚持的。😁

你好,如果你正巧看到这篇文章,并且觉得对你有益的话,就给个赞吧,让我感受一下分享的喜悦吧,蟹蟹。🤗

如若有写的有误的地方,也请大家不啬赐教!!

同样如若有存在疑惑的地方,请留言或私信,定会在第一时间回复你。

持续更新中

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java设计模式-装饰器模式
  • 一、装饰器模式介绍
    • 1)引入:
      • 2)概述
        • 3)角色结构
          • 4)使用场景
            • 5)举个例子
            • 二、装饰器模式实现
              • 2.1、前言
                • 2.2、代码实现
                • 三、总结
                  • 1、使用场景
                    • 2、优点:
                      • 3、缺点:
                      • 四、自言自语
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档