当前位置:网站首页>结构型模式-装饰者模式
结构型模式-装饰者模式
2022-07-27 03:46:00 【vbirdbest】
一:装饰者模式定义
在不改变现有对象结构的情况下,动态的给改对象增加一些职责(即增加其额外功能)的模式。
装饰者即继承某个类,又持有某个类的引用。
装饰(Decorator)模式中的角色:
- 抽象构件
- 具体构件
- 抽象装饰角色
- 具体装饰角色
二:案例
FastFood(快餐):抽象类,拥有价格、描述两个属性和一个抽象计算价格的方法。
/** * 快餐(抽象构件角色) */
public abstract class FastFood {
/** 价格 */
private float price;
/** 描述 */
private String desc;
public FastFood() {
}
public FastFood(float price, String desc) {
this.price = price;
this.desc = desc;
}
/** * 计算价格 */
public abstract float cost();
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
FriedRice:炒饭,属于快餐的一种,一个炒饭定义单价10元。
/** * 炒饭(具体构件角色) */
public class FriedRice extends FastFood {
public FriedRice() {
super(10, "炒饭");
}
@Override
public float cost() {
return getPrice();
}
}
FastFood fastFood = new FriedRice();
// 炒饭10.0元
System.out.println(fastFood.getDesc() + fastFood.cost() + "元");
new FriedRice(): 调用父类构造函数super(10, "炒饭"),将价格和描述传到FastFood中的price属性和desc属性。fastFood.cost()->FriedRice#cost()->FastFood#getPrice()最终获取到10元。
Gamish:装饰者类,即继承了快餐类FastFood,同时也持有快餐类的引用fastFood,该类也是一个抽象类没有实现快餐类的抽象方法cost()。
/** * 装饰者类(抽象装饰者角色) */
public abstract class Gamish extends FastFood {
private FastFood fastFood;
public Gamish(FastFood fastFood, float price, String desc) {
super(price, desc);
this.fastFood = fastFood;
}
public FastFood getFastFood() {
return fastFood;
}
public void setFastFood(FastFood fastFood) {
this.fastFood = fastFood;
}
}
Egg:鸡蛋,一个鸡蛋1元,继承装饰者类,提供一个有参构造函数,参数为快餐类。
/** * 鸡蛋(具体的装饰者角色) */
public class Egg extends Gamish {
// 有参构造函数需要提供快餐的主食
public Egg(FastFood fastFood) {
super(fastFood, 1, "鸡蛋");
}
@Override
public float cost() {
// 快餐价格 + 鸡蛋价格
return this.getFastFood().cost() + getPrice();
}
@Override
public String getDesc() {
return super.getDesc() + this.getFastFood().getDesc();
}
}
public static void main(String[] args) {
FastFood fastFood = new FriedRice();
// 炒饭10.0元
System.out.println(fastFood.getDesc() + fastFood.cost() + "元");
fastFood = new Egg(fastFood);
// 鸡蛋炒饭11.0元
System.out.println(fastFood.getDesc() + fastFood.cost() + "元");
}
new Egg(fastFood)->super(fastFood, 1, "鸡蛋"):将fastFood作为属性值保存下来,继续调用FastFood的构造方法super(price, desc):将价格和描述保存到FastFood类的price和desc属性上。fastFood.cost()->this.getFastFood().cost() + getPrice():获取fastFood即FriedRice.cost()=10元 + getPrice() = 1元 = 11元。
Bacon:培根,一个培根2元,在程序上也属于快餐的一种。
/** * 培根(具体的装饰者角色) */
public class Bacon extends Gamish {
public Bacon(FastFood fastFood) {
super(fastFood, 2, "培根");
}
@Override
public float cost() {
// 快餐价格 + 鸡蛋价格
return getFastFood().cost() + getPrice();
}
@Override
public String getDesc() {
return super.getDesc() + getFastFood().getDesc();
}
}
public class Client {
public static void main(String[] args) {
FastFood fastFood = new FriedRice();
// 炒饭10.0元
System.out.println(fastFood.getDesc() + fastFood.cost() + "元");
fastFood = new Egg(fastFood);
// 鸡蛋炒饭11.0元
System.out.println(fastFood.getDesc() + fastFood.cost() + "元");
fastFood = new Bacon(fastFood);
// 培根鸡蛋炒饭13.0元
System.out.println(fastFood.getDesc() + fastFood.cost() + "元");
}
}

public class Bacon extends Gamish {
@Override
public String getDesc() {
// super.getDesc()=培根 + getFastFood().getDesc()鸡蛋炒饭
// 此时getFastFood()=Egg
return super.getDesc() + getFastFood().getDesc();
}
}
public class Egg extends Gamish {
@Override
public String getDesc() {
// super.getDesc()=鸡蛋 + this.getFastFood().getDesc()=炒饭
// 此时this.getFastFood()=FriedRice
return super.getDesc() + this.getFastFood().getDesc();
}
}
public abstract class FastFood {
/** 描述 */
private String desc;
public String getDesc() {
return desc;
}
}

三:装饰者模式的好处
- 装饰者模式可以带来比集成更加灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承具有更具良好的扩展性,完美的遵循开闭原则,继承是静态的附加责任,装饰者则是动态的附加责任。
- 装饰类和被装饰类可以独立发展,不会相互耦合(例如增加一个炒河粉和增加一个胡萝卜都互不影响),装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
四:使用场景
- 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时,不能采用继承的情况主要有两类:
- 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,是的子类数目成爆炸性增长。
- 第二类是因为类定义不能继承(如 final).
- 在不影响其它对象的情况下,以动态、透明的方式给单个对象添加职责。
- 当对象的功能要求可以动态的添加,也可以再动态的撤销时。
五:装饰模式在JDK中的使用
public static void main(String[] args) throws Exception {
FileWriter fileWriter = new FileWriter("/text.txt");
BufferedWriter writer = new BufferedWriter(fileWriter);
}

BufferedWriter 继承Writer,并持有Writer的引用,BufferedWriter使用装饰者模式对Writer子实现进行了增强,添加了缓冲器,提高了写数据的效率。
public class BufferedWriter extends Writer {
private Writer out;
}
六:装饰者和静态代理的区别
- 相同点:
- 都要实现与目标类相同的业务接口。
- 在两个类中都要声明目标对象。
- 都可以在不修改目标类的 前提下增强目标方法。
- 不同点:
- 目的不同:
- 装饰者是为增强目标对象, 可以无限制的层层增强;
- 静态代理是为了保护和隐藏目标对象。
- 获取目标对象构建的地方不同:
- 装饰者是由外界传递进来的,可以通过构造方法传递;
- 静态代理是在代理类内部创建的,以此来隐藏目标对象。
- 类之间的关系不一样
- 静态代理对象和目标对象没有什么继承关系;
- 装饰者一般用在多个类,并且所有类都继承同一个父类。
- 目的不同:
边栏推荐
- Framework learning journey: init process startup process
- shel自动设置目录权限
- 佳明手表怎么设置用户定制显示
- Spark practice case (upgraded version)
- Is VR panorama just needed now? After reading it, you will understand
- Elastic certification test: 30 day FastPass Study Guide
- Okaleido tiger will log in to binance NFT in the second round, or continue to create sales achievements
- 【LeetCode】Day104-无重叠区间
- Do you know about wechat merchant billing?
- c# 获取uuid
猜你喜欢

电商分账系统重要吗,平台应该如何选择分账服务商呢?

2022-07-26:以下go语言代码输出什么?A:5;B:hello;C:编译错误;D:运行错误。 package main import ( “fmt“ ) type integer in

e.target与e.currentTarget的区别

The difference between ArrayList and LinkedList

2022-07-26: what is the output of the following go language code? A:5; B:hello; C: Compilation error; D: Running error. package main import ( “fmt“ ) type integer in

Rust:axum学习笔记(1) hello world
![[machine learning network] BP neural network and deep learning-6 deep neural networks (DNN)](/img/6a/02c76f5bd35b2d89e4f471b9b688f5.png)
[machine learning network] BP neural network and deep learning-6 deep neural networks (DNN)

js修改对象数组的key值

Eureka service registry

DINO 论文精度,并解析其模型结构 & DETR 的变体
随机推荐
php+swoole
利用JSON类型在mysql中实现数组功能
JMeter学习笔记004-CSV文件行数控制循环次数
BSN IPFS(星际文件系统)专网简介、功能、架构及特性、接入说明
Standard C language 13
Easy to use shell shortcuts
使用WebMvcConfigurer进行接口请求拦截进行中增强(附源码)
【小样本分割】MSANet: Multi-Similarity and Attention Guidance for Boosting Few-Shot Segmentation
BigDecimal pit summary & Best Practices
There are two solutions for the feign call header of microservices to be discarded (with source code)
[C language] recursively explain the tower of Hanoi problem
一张图看懂KingbaseES V9
Wechat applet rotation map
好用的shell快捷键
ISG指数显示,亚太区IT和商业服务市场在第二季度出现大幅下滑
Wechat input component adds a clear icon, and clicking clear does not take effect
【比赛参考】PyTorch常用代码段以及操作合集
[leetcode] day104 no overlapping interval
How to set user-defined display for Jiaming Watch
Detailed explanation of TCP protocol knowledge