装饰模式
在不改变原有对象的基础之上,动态地将额外的功能附加到该对象上,提供了比继承更有弹性的替代方案。
适用于:
拓展一个类的功能;
动态给对象添加功能,并且动态撤销。
优点:
继承的有力补充,不改变原有对象的情况下给对象拓展功能;
通过使用不同的装饰类、不同的组合方式,实现不同的效果。
符合开闭原则。
缺点:
装饰模式增加了许多子类,如果过度使用会使程序变得很复杂,增加程序复杂性;
装饰模式主要包含以下角色。
抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
比如去沙县吃面的时候,可以往面里加鸡蛋和肉末啥的,价格也会相应的调整,要支持不同食物自由组合,并计算相应的价格,则可以使用装饰模式来完成。
1.假设去沙县吃碗面,定义一个面条的抽象类,里面有备注和价格两个抽象方法
public abstract class NoodlesAbstract {
public abstract int price();
public abstract String remark();
}
2.定义一个面条抽象类的装饰器,继承自面条抽象类,重写抽象类的抽象方法
public abstract class NoodlesAbstractDecorator extends NoodlesAbstract {
private NoodlesAbstract noodles;
public NoodlesAbstractDecorator(NoodlesAbstract noodles) {
this.noodles = noodles;
}
@Override
public String remark(){
return noodles.remark();
}
@Override
public int price(){
return noodles.price();
}
}
3.创建初始的面条类,继承自面条抽象类
public class Noodles extends NoodlesAbstract{
@Override
public String remark(){
return "点了一碗面";
}
@Override
public int price(){
return 10;
}
}
4.定义一个鸡蛋装饰器继承自面条装饰器,吃面的时候可以加个蛋
public class EggDecorator extends NoodlesAbstractDecorator{
public EggDecorator(NoodlesAbstract noodles) {
super(noodles);
}
@Override
public String remark(){
return super.remark()+",加了一个蛋";
}
@Override
public int price(){
return super.price()+2;
}
}
5.定义一个肉末装饰器继承自面条装饰器,吃面的时候可以加点肉末
public class MeatDecorator extends NoodlesAbstractDecorator {
public MeatDecorator(NoodlesAbstract noodles) {
super(noodles);
}
@Override
public String remark(){
return super.remark()+",加了点肉末";
}
@Override
public int price(){
return super.price()+5;
}
}
6.测试输出,有两种写法
public class Test {
public static void main(String[]args){
//写法一
NoodlesAbstract noodles=new Noodles();
noodles=new EggDecorator(noodles);
noodles=new MeatDecorator(noodles);
System.out.println(noodles.remark()+" 价格要"+noodles.price()+"元");
//写法二
NoodlesAbstract noodles2=new Noodles();
//在括号里的会先加进去
noodles2=new EggDecorator(new MeatDecorator(noodles2));
System.out.println(noodles2.remark()+" 价格要"+noodles2.price()+"元");
}
}
//点了一碗面,加了一个蛋,加了点肉末 价格要17元
//点了一碗面,加了点肉末,加了一个蛋 价格要17元
通过不同的装饰器自由组合,我们可以灵活的加自己喜欢吃的东西,这是装饰模式的优点,但明显可以看出代码变复杂了。下一篇讲讲适配器模式