设计模型之装饰者模式
1. 装饰者模式
1.1 定义与特点
装饰(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。(有点像代理模式的功能,代理对象提供了与真实对象相同的方法,并可以扩展真实对象的功能)
装饰(Decorator)模式的主要优点有:
- 采用装饰模式扩展对象的功能比采用继承方式更加灵活。
- 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。
其主要缺点是:装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。
装饰者模式和桥接模式的区别:
桥接模式关注点是各维度的组合通过组合关系来实现,而装饰模式关注点时是在不改变现有对象结构的情况下,动态地给该对象增加一些职责。
1.2 模式的结构
装饰模式主要包含以下角色。
- 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
- 具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
- 抽象装饰(Decorator)角色:实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
- 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
1.3 问题由来
在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等。在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。如果采用继承的方式,随着扩展功能的增多,会造成子类会很膨胀。
1.4 解决思路
如果采用继承的方式,实现类对象扩展功能,会造成子类会很膨胀,所以我们在扩展类(装饰类)组合原对象类,这样当还要扩展新功能,只要把之前的扩展类放到新的扩展类,就可以叠加新功能了,并不改变原对象结构。
1.5 UML类图
1.6 解决方案
/**
* @author 26530
* 奶茶
*/
public interface MilkTea
{
String getMilkName();
float getPrice();
}
/**
* @author 26530
* 珍珠奶茶
*/
public class PearlMilkTea implements MilkTea{
@Override
public String getMilkName()
{
return "珍珠奶茶";
}
@Override
public float getPrice()
{
return 10;
}
}
/**
* @author 26530
* 巧克力奶茶
*/
public class ChocolateMilkTea implements MilkTea{
@Override
public String getMilkName()
{
return "巧克力奶茶";
}
@Override
public float getPrice()
{
return 11;
}
}
/**
* @author 26530
* 烧仙草
*/
public class HerbalJellyMilkTea implements MilkTea{
@Override
public String getMilkName() {
// TODO Auto-generated method stub
return "烧仙草";
}
@Override
public float getPrice() {
// TODO Auto-generated method stub
return 15;
}
}
/**
* @author 26530
* 口味
*/
public abstract class AddTasteMilkTea implements MilkTea
{
abstract String getState();
MilkTea milkTea;
public MilkTea getMilkTea()
{
return milkTea;
}
public void setMilkTea(MilkTea milkTea)
{
this.milkTea = milkTea;
}
public String getMilkName()
{
// TODO Auto-generated method stub
return this.milkTea.getMilkName();
}
public float getPrice()
{
// TODO Auto-generated method stub
return this.milkTea.getPrice();
}
}
/**
* @author 26530
* 少冰
*/
public class AddHalfIceMilkTea extends AddTasteMilkTea{
@Override
public String getState()
{
return "少冰";
}
@Override
public String getMilkName()
{
return super.getMilkName() + getState();
}
@Override
public float getPrice()
{
return super.getPrice();
}
public AddHalfIceMilkTea(MilkTea milkTea) {
super.milkTea = milkTea;
}
}
/**
* @author 26530
* 去冰
*/
public class AddNoIceMilkTea extends AddTasteMilkTea{
@Override
public String getState()
{
return "去冰";
}
public String getMilkName()
{
return super.getMilkName() + getState();
}
public float getPrice()
{
return super.getPrice();
}
public AddNoIceMilkTea(MilkTea milkTea) {
super.milkTea = milkTea;
}
}
/**
* @author 26530
* 全糖
*/
public class AddNormalSugerMilkTea extends AddTasteMilkTea{
@Override
public String getState() {
// TODO Auto-generated method stub
return "全糖";
}
public String getMilkName()
{
return super.getMilkName() + getState();
}
public float getPrice()
{
return super.getPrice();
}
public AddNormalSugerMilkTea(MilkTea milkTea) {
super.milkTea = milkTea;
}
}
/**
* @author 26530
* 无糖
*/
public class AddSugarFreeMilkTea extends AddTasteMilkTea {
@Override
public String getState() {
// TODO Auto-generated method stub
return "无糖";
}
public String getMilkName()
{
return super.getMilkName() + getState();
}
public float getPrice()
{
return super.getPrice();
}
public AddSugarFreeMilkTea(MilkTea milkTea)
{
super.milkTea = milkTea;
}
}
/**
* @author 26530
* 选择大杯,中杯,小杯
*/
public abstract class ChooseCapacityMilkTea implements MilkTea
{
abstract String getSize();
MilkTea milkTea;
public MilkTea getMilkTea() {
return milkTea;
}
public void setMilkTea(MilkTea milkTea) {
this.milkTea = milkTea;
}
public String getMilkName()
{
return this.milkTea.getMilkName();
}
public float getPrice()
{
return this.milkTea.getPrice();
}
}
/**
* @author 26530
* 大杯
*/
public class LargeMilkTea extends ChooseCapacityMilkTea{
@Override
public String getSize()
{
return "大杯";
}
public String getMilkName()
{
return getSize() + super.getMilkName() ;
}
public float getPrice()
{
return super.getPrice() + 5;
}
public LargeMilkTea(MilkTea milkTea) {
super.milkTea = milkTea;
}
}
/**
* @author 26530
* 中杯
*/
public class MediumMilkTea extends ChooseCapacityMilkTea{
@Override
public String getSize()
{
return "中杯";
}
public String getMilkName()
{
return getSize() + super.getMilkName() ;
}
public float getPrice()
{
return super.getPrice() + 3;
}
public MediumMilkTea(MilkTea milkTea) {
super.milkTea = milkTea;
}
}
/**
* @author 26530
* 小杯
*/
public class SmallMilkTea extends ChooseCapacityMilkTea{
@Override
public String getSize()
{
return "小杯";
}
public String getMilkName()
{
return getSize() + super.getMilkName() ;
}
public float getPrice()
{
return super.getPrice() ;
}
public SmallMilkTea(MilkTea milkTea)
{
super.milkTea = milkTea;
}
}
public class Test
{
public static void main(String[] args)
{
PearlMilkTea pearlMilkTea = new PearlMilkTea();
System.out.println(pearlMilkTea.getMilkName());
System.out.println(pearlMilkTea.getPrice());
LargeMilkTea capacity = new LargeMilkTea(pearlMilkTea);
AddSugarFreeMilkTea addSugarFreeMilkTea = new AddSugarFreeMilkTea(capacity);
System.out.println(addSugarFreeMilkTea.getMilkName());
System.out.println(addSugarFreeMilkTea.getPrice());
/*
珍珠奶茶
10.0
大杯珍珠奶茶无糖
15.0
*/
}
}