一、概念
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
二、结构图
三、使用场景
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
四、实例一
饮料店里卖多种饮品,有可乐、啤酒、奶茶等等。
1、先建一个component
/**
* <p>标题:Drinks </p>
* <p>描述: 饮料接口</p>
*/
public abstract class Drinks {
String name;
public abstract int price();
public String getName(){
return name;
}
}
2、建三个concreteComponent
(1)、奶茶实现类
/**
* <p>标题: MilkyTeaComponent</p>
* <p>描述: 奶茶实现类</p>
*/
public class MilkyTeaComponent extends Drinks{
/**
* @Title:构造方法
*/
public MilkyTeaComponent() {
name="奶茶";
}
/*
* 奶茶的价格
*/
@Override
public int price() {
return 10;
}
}
(2)、可乐实现类
/**
* <p>标题: ColaComponent</p>
* <p>描述: 可乐实现类</p>
*/
public class ColaComponent extends Drinks{
/**
* @Title:构造方法
*/
public ColaComponent() {
name="可乐";
}
/*
* <p>描述:可乐价格 </p>
*/
@Override
public int price(){
return 5;
}
}
(3)、啤酒实现类
/**
* <p>标题: BeerComponent</p>
* <p>描述: 啤酒实现类</p>
*/
public class BeerComponent extends Drinks{
/**
* @Title:构造方法
*/
public BeerComponent() {
name="啤酒";
}
/*
* <p>啤酒的价格</p>
*/
@Override
public int price() {
return 3;
}
}
3、创建Decorator
/**
* <p>标题: Decorator</p>
* <p>描述:装饰抽象类 </p>
*/
public abstract class Decorator extends Drinks{
protected Drinks drinks;
public Decorator(Drinks yp){
this.drinks=yp;
}
}
4、创建concreteDecorator
(1)、加冰饮料
/**
* <p>标题: IceDecorator</p>
* <p>描述: 加冰饮料</p>
*/
public class IceDecorator extends Decorator{
/**
* @Title:构造方法
* @param drinks
*/
public IceDecorator(Drinks drinks) {
super(drinks);
}
public void 加冰(){
System.out.println("饮料加冰,夏天喝最爽口哦");
}
/*
* <p>描述:加冰饮料的价格,比普通饮料贵三块</p>
*/
@Override
public int price() {
return 3+drinks.price();
}
/*
* <p>描述: 饮料名</p>
* @return
*/
@Override
public String getName() {
加冰();
return "加了冰的"+ drinks.getName();
}
}
(2)、加水饮料
/**
* <p>标题: Water水Decorator</p>
* <p>描述: 加水饮料</p>
*/
public class WaterDecorator extends Decorator{
/**
* @Title:构造方法
* @param drinks
*/
public WaterDecorator(Drinks drinks) {
super(drinks);
}
public void 兑水(){
System.out.println("饮料兑水。。。");
}
/*
* <p>加水饮料价格,比普通饮料贵2块 </p>
*/
@Override
public int price() {
return 2+drinks.price();
}
/*
* <p>饮料名</p>
*/
@Override
public String getName() {
兑水();
return "对了水的"+drinks.getName();
}
}
5、测试
public static void main(String[] args) {
Drinks drink1=new ColaComponent();
drink1=new WaterDecorator(drink1);
System.out.println("饮品名:"+drink1.getName()+";价格:"+drink1.price());
Drinks drink2=new BeerComponent();
drink2=new IceDecorator(drink2);
System.out.println("饮料名:"+drink2.getName()+";价格:"+drink2.price());
Drinks drink3=new MilkyTeaComponent();
drink3=new IceDecorator(drink3);
System.out.println("饮料名:"+drink3.getName()+";价格:"+drink3.price());
}
运行结果:
饮料兑水。。。
饮品名:对了水的可乐;价格:7
饮料加冰,夏天喝最爽口哦
饮料名:加了冰的啤酒;价格:6
饮料加冰,夏天喝最爽口哦
饮料名:加了冰的奶茶;价格:13
五、实例二
人穿衣服,不同的搭配是不同的装饰。
1、创建concreteDecorator,由于只有一个创建concreteDecorator,因此不需要抽象component
/**
* <p>标题: Person</p>
* <p>描述: 具体的concreteComponent,由于只有个concreteComponent,因此不需要创建Component</p>
*/
public class Person {
public Person(){}
private String name;
public Person(String name){
this.name=name;
}
public void show(){
System.out.println("装扮的:"+name);
}
}
2、创建Decorator:Finery
/**
* <p>标题: Finery</p>
* <p>描述: 装饰类</p>
*/
public class Finery extends Person{
protected Person person;
public Finery(Person person){
this.person=person;
}
/*
* <p>展示</p>
*/
@Override
public void show() {
person.show();
}
}
3、创建concreteDecorator
(1)、T恤
/**
* <p>标题: TShirt</p>
* <p>描述: T恤</p>
*/
public class TShirt extends Finery{
/**
* @Title:构造方法
* @param person
*/
public TShirt(Person person) {
super(person);
}
/*
* <p>描述: 展示 </p>
*/
@Override
public void show() {
System.out.println("穿T-shirt");
}
}
(2)、短裤
/**
* <p>标题: BigTrouser</p>
* <p>描述: 短裤</p>
*/
public class BigTrouser extends Finery{
/**
* @Title:构造方法
* @param person
*/
public BigTrouser(Person person) {
super(person);
}
/*
* <p>描述:展示</p>
*/
@Override
public void show() {
System.out.println("穿短裤");
}
}
(3)、西装
/**
* <p>标题: WearSuit</p>
* <p>描述: 西装</p>*/
public class WearSuit extends Finery{
/**
* @Title:构造方法
* @param person
*/
public WearSuit(Person person) {
super(person);
}
/*
* <p>描述:展示 </p>
*/
@Override
public void show() {
System.out.println("西装");
}
}
4、测试
public static void main(String[] args) {
Person person=new Person("小明");
Finery tshirts=new TShirt(person);
Finery bigTrouser=new BigTrouser(person);
tshirts.show();
bigTrouser.show();
person.show();
}
运行结果:
穿T-shirt
穿短裤
装扮的:小明
六、装饰模式的优点
装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。通过使用装饰模式,设计者可以设计出不同的组合。
七、装饰模式的缺点
由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。