装饰模式
装饰模式
允许向一个现有的对象动态地添加新的功能,同时不改变其结构。它是继承的一种替代方案,可以动态地扩展对象。有点像静态代理
角色
装饰者模式有四种角色 抽象被装饰者,被装饰者,装饰者和抽象被装饰者
- 抽象被装饰者:一般是一个接口,包含需要被装饰的方法
- 被装饰者:实现 抽象被装饰者 接口,代表被装饰的原始对象。
- 抽象装饰者:继承或实现抽象被装饰者,内部含有一个 抽象被装饰者的属性,调用或增强 被装饰者的方法
- 装饰者:实现抽象装饰者的方法,给被装饰对象增加具体的职责
案例
今天不开包子店,想开一家奶茶店。产品有普通奶茶,为了奶茶种类丰富,需要支持添加多种小料,椰果,芋圆等,且可以自由组合。
根据要求,先建立起基础类
接口 Tea,用来表示 抽象被装饰类,MilkTea 用来表示 被装饰类
/**
* 抽象被装饰者
**/
public interface Tea {
String getName();
int getPrice();
}
/**
* 被装饰者:奶茶
**/
public class MilkTea implements Tea{
@Override
public String getName() {
return "奶茶";
}
@Override
public int getPrice() {
return 10;
}
}
分析下问题,想要支持可以自由组合的方式来 增强奶茶类,普通的继承和组合 很难实现。所以才使用装饰者模式
下面是装饰者的代码
/**
* 抽象装饰者:奶茶小料
**/
public abstract class AbsDecoratorIngredients implements Tea{
final private Tea tea;
public AbsDecoratorIngredients(Tea tea) {
this.tea = tea;
}
@Override
public int getPrice() {
//执行目标对象原本的行为
return tea.getPrice();
}
@Override
public String getName() {
//执行目标对象原本的行为
return tea.getName();
}
}
/**
* 装饰者:椰果
**/
public class DecoratorCoconut extends AbsDecoratorIngredients{
public DecoratorCoconut(Tea tea) {
super(tea);
}
@Override
public int getPrice() {
/*被装饰者的价格 + 当前椰果的价格*/
return super.getPrice() + 2;
}
@Override
public String getName() {
return super.getName() + " + " + "椰果";
}
}
/**
* 装饰者:芋圆
**/
public class DecoratorTaroBall extends AbsDecoratorIngredients{
public DecoratorTaroBall(Tea tea) {
super(tea);
}
@Override
public int getPrice() {
/*被装饰者的价格 + 当前椰果的价格*/
return super.getPrice() + 2;
}
@Override
public String getName() {
return super.getName() + " + " + "椰果";
}
}
测试代码:
public class DecoratorTest {
public static void main(String[] args) {
/*给我一杯奶茶*/
System.out.println("==========================给我一杯奶茶====================================");
Tea milkTea = new MilkTea();
System.out.println(milkTea.getName() + " = " + milkTea.getPrice());
/*给我一杯珍珠奶茶*/
System.out.println("===========================给我一杯珍珠奶茶===================================");
milkTea = new DecoratorTaroBall(milkTea);
System.out.println(milkTea.getName() + " = " + milkTea.getPrice());
/*给我一杯珍珠椰果奶茶*/
System.out.println("============================给我一杯珍珠椰果奶茶==================================");
milkTea = new DecoratorCoconut(milkTea);
System.out.println(milkTea.getName() + " = " + milkTea.getPrice());
}
}
输出:
==========================给我一杯奶茶====================================
奶茶 = 10
===========================给我一杯珍珠奶茶===================================
奶茶 + 椰果 = 12
============================给我一杯珍珠椰果奶茶==================================
奶茶 + 椰果 + 椰果 = 14
看到这里,可能有人发现 抽象装饰者类 好像可以省略。
是的,这个例子是可以省略的,
这里只是写的 装饰者模式的标准写法。使用一个抽象装饰者 是为了 将 抽象被装饰者 和 装饰者 解耦。
一旦把 抽象装饰者省略,大家可能发现这个写法是不是很眼熟,是不是很像 静态代理。
其实 设计模式 就是这样,23种设计模式只是应对不同的场景,不同的设计模式总会有相似之处。
设计模式来源于设计原则,万变不离其宗,稍微变换下就是另一种设计模式。
下面看下 装饰和静态代理的区别
装饰模式与静态代理的区别
装饰模式:目标对象由外界传入,目的是为了增强该对象
静态代理:目标对象由内部生成,目的是隐藏和保护该对象
装饰模式一般会迭代传入不同的对象,一步一步的增强方法
静态代理一般只传入一个对象,只调用一层