详解Java设计模式中的装饰模式

网友投稿 236 2022-09-05


详解Java设计模式中的装饰模式

目录一、装饰模式的定义和特点二、装饰模式的结构三、咖啡点单案例演示四、总结

一、装饰模式的定义和特点

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

就像我们做菜,需要用到调料,菜,刀,火等一系列抽象的组件来最终完成一道菜。

装饰模式的定义:

指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。就增加功能来说,装饰模式比生成子类更加灵活。

特点:

- 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用

- 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果

- 装饰器模式完全遵守开闭原则

缺点

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

二、装饰模式的结构

装饰模式的结构一般包含以下几个角色

1. 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。

2. 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。

3. 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。

4. 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

图示

三、咖啡点单案例演示

有一个需求,点一杯咖啡需要咖啡,材料等等,这个案例就很适合装饰模式,类似于穿衣,点餐,买包子,等等,我们怎么把他设计成装饰模式呢?

看类图

这个结构就是我已经设计好的一个装饰模式的类图,idea自动生成的,这里的Drink就是我们上面说的抽象构建角色,装饰者是Decorator,他是一个抽象装饰,下面他的子类就是具体的装饰者,那么具体构建中间我们提供了一个中间构建,提供了coffee的一些共性,可以放在这里,用的时候直接继承,他的下面就是相应的具体构件,具体被装饰者角色,装饰者与被装饰者共同继承自component抽象构件,需要用到装饰的就是我们点一杯咖啡,用装饰去包裹即可,层层包裹,案例如下:

比如我要点一份加糖加奶的拿铁咖啡

代码实例:

component抽象构件角色:

package com.decoratorPattern.starBucks;

/**

* @author wang

* @version 1.0

* @packageName com.decoratorPattern.starBucks

* @className Drink

* @date 2021/12/28 10:28

* @Description 饮料构件类抽象component

*/

public abstract class Drink {

private String description;

private float price = 0.0f;

public String getDescription() {

return description;

}

public void setDescription(String description) {

this.description = description;

}

public float getPrice() {

return price;

}

public void setPrice(float price) {

this.price = price;

}

/**

* @Date 2021/12/28 10:30

* @Param

* @Return float

* @MetodName cost

* @Author wang

* @Description 计算花费,订单价格

*/

public abstract float cost();

}

装饰者类:

package com.decoratorPattern.starBucks;

/**

* @author wang

* @version 1.0

* @packageName com.decoratorPattern.starBucks

* @className Decorator

* @date 2021/12/28 10:40

* @Description 装饰者定义类,配料

*/

public class Decorator extends Drink {

private Drink drink;

/**

* @param drink

* @Date 2021/12/28 10:42

* @Param

* @Return null

* @MetodName Decorator

* @Author wang

* @Description 传入一个被装饰者,由装饰者进行装饰

*/

public Decorator(Drink drink) {

this.drink = drink;

}

/**

* @Date 2021/12/28 10:43

* @Param

* @Return float

* @MetodName cost

* @Author wang

* @Description 装饰者的价格加上被装饰者的价格

*/

@Override

public float cost() {

return super.getPrice() + drink.cost();

}

/**

* @Date 2021/12/28 10:44

* @Param

* @Return String

* @MetodName getDescription

* @Author wang

* @Description 输出订单信息,包含装饰者,装饰者的价格,以及被装饰者的信息

*/

@Override

public String getDescription() {

return drink.getDescription() + "\n加入的材料:" + super.getDescription()

+ "\t材料价格:" + super.getPrice() ;

}

}

package com.decoratorPattern.starBucks;

/**

* @author wang

* @version 1.0

* @packageName com.decoratorPattern.starBucks

* @className Coffee

* @date 2021/12/28 10:31

* @Description 咖啡类

*/

public class Coffee extends Drink{

@Override

public float cost() {

return super.getPrice();

}

}

具体构件类:拿铁

package com.decoratorPattern.starBucks;

/**

* @author wang

* @version 1.0

* @packageName com.decoratorPattern.starBucks

* @className latte

* @date 2021/12/28 10:32

* @Description 拿铁咖啡实类,被装饰者

*/HahjQTfgXn

public class Latte extends Coffee{

public Latte() {

setDescription("拿铁咖啡");

setPrice(15.0f);

}

}

具体构件类:摩卡

package com.decoratorPattern.starBucks;

/**

* @author wang

* @version 1.0

* @packageName com.decoratorPattern.starBucks

* @className Mocha

* @date 2021/12/28 10:36

* @Description 摩卡咖啡实类,被装饰者

*/

public class Mocha extends Coffee {

public Mocha() {

setDescription("摩卡咖啡");

setPrice(12.2f);

}

}

其他同上,不过多展示

具体装饰类:牛奶

package com.decoratorPattern.starBucks;

/**

* @author wang

* @version 1.0

* @packageName com.decoratorPattern.starBucks

* @className Milk

* @date 2021/12/28 10:47

* @Description 牛奶调味品,具体装饰者

*/

public class Milk extends Decorator{

/**

* @param drink

* @Date 2021/12/28 10:42

* @Param

* @Return null

* @MetodName Decorator

* @Author wang

* @Description 传入一个被装饰者,由装饰者进行装饰

*/

public Milk(DrHahjQTfgXnink drink) {

super(drink);

setDescription("牛奶");

setPrice(1.0f);

}

}

具体装饰:糖

package com.decoratorPattern.starBucks;

/**

* @author wang

* @version 1.0

* @packageName com.decoratorPattern.starBucks

* @className sugar

* @date 2021/12/28 10:50

* @Description 糖,装饰者

*/

public class Sugar extends Decorator{

/**

* @param drink

* @Date 2021/12/28 10:42

* @Param

* @Return null

* @MetodName Decorator

* @Author wang

* @Description 传入一个被装饰者,由装饰者进行装饰

*/

public Sugar(Drink drink) {

super(drink);

setDescription("糖");

setPrice(0.5f);

}

}

订单测试代码:

package com.decoratorPattern.starBucks;

/**

* @author wang

* @version 1.0

* @packageName com.decoratorPattern.starBucks

* @className OrderTest

* @date 2021/12/28 10:51

* @Description 前台订单类

*/

public class OrderTest {

public static void main(String[] args) {

//点一份加糖加奶的拿铁咖啡

System.out.println("+++++++没加任何东西+++++++");

Drink latte = new Latte();

System.out.println("当前总价:" + latte.cost());

System.out.println("coffee:" +latte.getDescription());

//加糖

System.out.println("+++++++加糖后+++++++");

latte = new Sugar(latte);

System.out.println("当前总价:" + latte.cost());

System.out.println("coffee:" + latte.getDescription());

System.out.println("+++++++加奶后+++++++");

latte = new Milk(latte);

System.out.println("当前总价:" + latte.cost());

System.out.println("coffee:" +latte.getDescription());

}

}

/**

* +++++++没加任何东西+++++++

* 当前总价:15.0

* coffee:拿铁咖啡

* +++++++加糖后+++++++

* 当前总价:15.5

* coffee:拿铁咖啡

* 加入的材料:糖 材料价格:0.5

* +++++++加奶后+++++++

* 当前总价:16.5

* coffee:拿铁咖啡

* 加入的材料:糖 材料价格:0.5

* 加入的材料:牛奶 材料价格:1.0

*

* Process finished with exit code 0

*/

综上, 如果我们需要新的咖啡种类或者是新的调料,只需要新增类去继承coffee或者decorator类即可。

四、总结

装饰模式是为已有的功能动态的添加更多功能的一种方式,当系统需要新功能的时候,向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为。

优点:

把类中装饰功能从类中移除,这样可以简化原来的类,

有效的把类的核心职责和装饰功能分开了,而且可以去除相关类中的重复装饰逻辑

可代替继承。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【图像加密】图像加密解密含Matlab源码(图像加密解密算法)
下一篇:Python学习笔记|字符串与正则表达式练习下(python正则判断字符串)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~