设计模式之装饰者模式
引例
需求:假设现在有烧饵块:白米饵块(WhiteRice),紫米饵块(PurpleRice),黄米饵块(yellowRice),调料有热狗(HotDog),油条(oilNoodle),鸡柳(chicken),客户可以单点白米的,或者白米+调料的组合,计算相应的费用,要求在扩展饵块种类的时候,具有良好的扩展性,改动维护方便。
一般解法
方案一
类图分析:
-
ShaoErkuai是一个抽象类
-description就是对烧饵块的描述,比如是白米,还是紫米。
-cost()方法就是计算费用,ShaoErKuai中做成一个抽象方法。
-
PurpleRice就是单种烧饵块,继承了ShaoErKuai,并实现了cost()方法。
-
WhiteRice&&HotDog就是白米的+热狗,这个组合可以很多。
问题:这样设计会有很多类,当我们增加一种烧饵块,或者一个新的调料时,类的数量会倍增,就会出现类爆炸。
方案二
1) 方案 2 可以控制类的数量,不至于造成很多的类
2) 考虑到用户可以添加多份调料,可以将 hasHotDog返回一个对应 int
3) 问题:在增加或者删除调料种类时,需要加上新的方法,并修改基类中的cost()方法。这种设计违反了开放关闭原则(类应该对扩展开放,对修改关闭。)
4) 改进:考虑使用 装饰者 模式
装饰者模式介绍
装饰者模式(Decorator Pattern)是结构型模式,也称装饰器模式/修饰模式。
定义:它可以动态的将新功能附加到对象上,同时又不改变其结构。在对象功能扩展方面,它比继承更有弹性。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法结构完整性的前提下,提供了额外的功能。
类图:
- Component抽象类:主体,比如类似前面的
ShaoErKuai
。 - ConcreteComponent类:具体的主体,比如前面的白米饵块。
- Decorator类:装饰者,比如前面的调料
- ConcreteDecorator类:具体的装饰者,比如前面的热狗或者油条。
装饰者解法实现
类图:
Decorator 是一个装饰类,含有一个被装饰的对象(ShaoErKuai obj)和的cost()方法进行一个费用的叠加计算,递归的计算价格。
HotDog和OilNoodle是具体的装饰者
ShaoErKuai是被装饰者主体
WhiteRice和PurpleRice是具体实现的被装饰者实体
代码实现:
1.抽象类
package day08_decorator.test01;
import lombok.Data;
/**
* @author coolsheep
* @date 2023/4/3 22:02
* @Describe 烧饵块抽象类
*/
@Data
public abstract class ShaoErKuai {
public String description;
private float price = 0.0f;
/**
* 用来返回烧饵块的价格,需要在具体类中自己实现
*
* @return
*/
public abstract float cost();
}
2.被装饰者
/**
* @author coolsheep
* @date 2023/4/3 22:06
* @Describe
*/
public class WhiteRice extends ShaoErKuai {
public WhiteRice() {
setDescription("白米烧饵块");
setPrice(3.0f);
}
@Override
public float cost() {
return super.getPrice();
}
}
3.装饰者
/**
* @author coolsheep
* @date 2023/4/3 22:04
* @Describe 装饰者
*/
public class Decorator extends ShaoErKuai {
private ShaoErKuai obj;
public Decorator(ShaoErKuai obj) {//组合
this.obj = obj;
}
@Override
public float cost() {
return super.getPrice() + obj.cost();
}
@Override
public String getDescription() {
//obj.getDescription()输出被装饰者的信息
return description + ":" + getPrice() + " && " + obj.getDescription() + ":" + obj.getPrice();
}
}
/**
* @author coolsheep
* @date 2023/4/3 22:32
* @Describe 具体的装饰类
*/
public class HotDog extends Decorator{
public HotDog(ShaoErKuai obj) {
super(obj);
setDescription("热狗");
setPrice(1.5f);
}
}
/**
* @author coolsheep
* @date 2023/4/3 22:35
* @Describe 具体的装饰类
*/
public class OilNoodle extends Decorator {
public OilNoodle(ShaoErKuai obj) {
super(obj);
setDescription(" 油条 ");
setPrice(2.0f);
}
}
4.客户端测试
/**
* @author coolsheep
* @date 2023/4/3 22:37
* @Describe
*/
public class Client {
public static void main(String[] args) {
//需求:点一份白米饵块+热狗+油条
//点一份白米饵块
ShaoErKuai order = new WhiteRice();
System.out.println("order 费用=" + order.cost());
System.out.println("order 订单描述=" + order.getDescription());
//order 加一份热狗
order = new HotDog(order);
System.out.println("order 加一份热狗,费用="+order.cost());
System.out.println("order 加一份热狗,订单描述="+order.getDescription());
order = new OilNoodle(order);
System.out.println("order 加了一份油条,费用="+order.cost());
System.out.println("order 加了一份油条,订单描述="+order.getDescription());
}
}
小结
桥接模式和装饰者模式的区别:
桥接模式是为了实现两个没有关联的维度的东西的自由组合,这里没有关联是指各自拥有自己的属性和方法,没有相同点(使用聚合或者组合)。装饰者模式使用了继承必然是两个种类具有相同的一些属性和方法,它不是为了实现两个维度的自由组合,是为了实现对对象的一层一层又一层包装,调用方法时,每一层包装递归的调用上一层的包装。
这里的包装可以举一个例子,如同月饼的包装,可以包一层,再包一层,再包一层,每一层的包装可以形同也可以不同。装饰者模式将月饼传入装饰类,每包一次就将上一次包好的月饼传入装饰类,进行下一次的包装。
标签:Day08,obj,public,装饰,cost,设计模式,ShaoErKuai,order From: https://www.cnblogs.com/coolsheep/p/17324072.html