属于结构型模式。目的是在不改变原有对象的基础上,将功能附加到对象上,提供了比继承更加有弹性的替代方案(拓展原有对象的功能)
示例
比如买煎饼这个事情,如果不使用装饰器,只是简单的使用继承,会需要用到很多类
纯煎饼类
如果不使用装饰器
/**
* 煎饼类
*/
public class BetterCake {
/**
* 名字
* @return String
*/
protected String getMsg(){
return "煎饼";
}
/**
* 价格
* @return int
*/
public int price(){
return 5;
}
}
煎饼+一个鸡蛋
/**
* 煎饼+鸡蛋
*/
public class BetterCakeWithEgg extends BetterCake {
@Override
protected String getMsg() {
return super.getMsg()+"+1个鸡蛋";
}
/**
* 加鸡蛋后。价格上涨1元
* @return
*/
@Override
public int price() {
return super.price()+1;
}
}
煎饼+一个鸡蛋+一个香肠
/**
* 煎饼+鸡蛋+香肠
*/
public class BetterCakeWithEggAndSausage extends BetterCakeWithEgg {
@Override
protected String getMsg() {
return super.getMsg()+"+1个香肠";
}
/**
* 加香肠后。价格再上涨2元
* @return
*/
@Override
public int price() {
return super.price()+2;
}
}
测试
public static void main(String[] args) {
//纯煎饼
BetterCake betterCake = new BetterCake();
System.out.println(betterCake.getMsg()+",价格:"+betterCake.price()+"元");
//煎饼+鸡蛋
BetterCake betterCakeWithEgg = new BetterCakeWithEgg();
System.out.println(betterCakeWithEgg.getMsg()+",价格:"+betterCakeWithEgg.price()+"元");
//煎饼+鸡蛋+香肠
BetterCake betterCakeWithEggAndSausage = new BetterCakeWithEggAndSausage();
System.out.println(betterCakeWithEggAndSausage.getMsg()+",价格:"+betterCakeWithEggAndSausage.price()+"元");
}
结果
【缺点】此种方法过于死板,如果要添加多个鸡蛋或多个香肠(即需求发生变更时),都需要重新新建一个类,不便于管理。
使用装饰器
可以只创建一种菜,而后随意加多少数量。
准备一个煎饼模板
/**
* 由于煎饼会经常变更,故不实现具体的类,而是定义一个抽象的煎饼类
*/
public abstract class BetterCake {
/**
* 名字-子类实现
* @return String
*/
protected abstract String getMsg();
/**
* 价格-子类实现
* @return int
*/
protected abstract int price();
}
准备一个煎饼的基础套餐–纯煎饼
/**
* 基础套餐
*/
public class BaseBetterCake extends BetterCake {
@Override
protected String getMsg() {
return "煎饼";
}
@Override
protected int price() {
return 5;
}
}
准备一个装饰器,用来给煎饼添加菜,但是加什么还未定
/**
* 煎饼包装器的抽象类
*/
public abstract class BaseBetterCakeDecorator extends BetterCake {
/**
* 需要包装的煎饼
*/
private BetterCake betterCake;
/**
* 通过有参构造传入需要包装的煎饼
* @param betterCake
*/
public BaseBetterCakeDecorator(BetterCake betterCake) {
this.betterCake = betterCake;
}
@Override
protected String getMsg() {
return this.betterCake.getMsg();
}
@Override
protected int price() {
return this.betterCake.price();
}
}
添加鸡蛋的装饰:先传入原有的煎饼,而后返回加好鸡蛋的煎饼
/**
* 鸡蛋的装饰
*/
public class EggDecorator extends BaseBetterCakeDecorator{
/**
* 通过有参构造传入需要包装的煎饼
*
* @param betterCake
*/
public EggDecorator(BetterCake betterCake) {
super(betterCake);
}
@Override
protected String getMsg() {
return super.getMsg()+"+一个鸡蛋";
}
@Override
protected int price() {
return super.price()+1;
}
}
同理建立加香肠的类
/**
* 加香肠装饰
*/
public class SausageDecorator extends BaseBetterCakeDecorator{
/**
* 通过有参构造传入需要包装的煎饼
*
* @param betterCake
*/
public SausageDecorator(BetterCake betterCake) {
super(betterCake);
}
@Override
protected String getMsg() {
return super.getMsg()+"+一个香肠";
}
@Override
protected int price() {
return super.price()+2;
}
}
测试:
public static void main(String[] args) {
//准备了一个煎饼的模板--静态代理
BetterCake betterCake;
//准备了一个煎饼的基础套餐
betterCake= new BaseBetterCake();
//加鸡蛋,得到一个加了鸡蛋后的煎饼
betterCake = new EggDecorator(betterCake);
//再加一个鸡蛋,得到一个加了2个鸡蛋的煎饼
betterCake = new EggDecorator(betterCake);
//再加一个香肠,得到一个加了2个鸡蛋和一个香肠的煎饼
betterCake = new SausageDecorator(betterCake);
//如果还需要加其他菜种,则新建这个种类的类,即可添加任意数量
System.out.println(betterCake.getMsg()+",价格:"+betterCake.price()+"元");
}
结果
类关系图
打开依赖显示:
装饰器模式与静态代理的区别:【is-a】父子关系
装饰器始终强调【is-a】,即最终还是这个对象,只是添加了一些新的东西。就算加上了蛋、香肠,但它依然是煎饼-BetterCake;(子类既可以纵向扩展父类的功能[即在基础套餐的基础上决定由多少种菜可以加],又很灵活,可以由用户决定要横向拓展多少[即每种菜加多少]),在功能上,要么是调用父类功能,要么是扩展新功能,要么是覆盖,不会对原有功能增强。
代理模式到了最后确有可能不再满足【is-a】了,而是变成了一个其他的对象【媒婆】。静态代理会做功能的增强,在原有方法的前后加入新的逻辑。