设计模式之装饰器模式

1装饰器模式

1.1装饰器模式定义

装饰器模式(Decorator Pattern),也叫包装模式 Wrapper Pattern

是指在不改变原有对象的基础之上,将功能附加到对象上.提供了比继承更灵活的替代方法 属于结构型模式.

1.2装饰器的UML类图

在这里插入图片描述
从类图分析 主要包含4种角色
抽象组件(Component):可以是一个接口或者抽象类:其充当被装饰类的原始对象,定义了被装饰的对象方法(既 抽出公用的方法)
具体实现类(ConcreteComponent): 继承/实现Component的一个具体对象,也是被装饰对象
抽象装饰器(Decorator)* 通用的装饰ConcreteComponent的装饰器,Decorator其内部必然有个属性指向Component 抽象组件;里面一般包含的是抽象类/接口,主要是为了让其子类按照其构造形式传入一
个 Component 抽象组件,这是强制的通用行为(当然,如果系统中装饰逻辑单一,并不需要实现许
多装饰器,那么我们可以直接省略该类,而直接实现一个具体装饰器(ConcreteDecorator)即可);

具体装饰器(ConcreteDecorator):Decorator 的具体实现类,理论上,每个 ConcreteDecorator
都扩展了Component对象的一种功能;

1.3装饰器的使用场景

1.用于拓展一个类的功能或者给一个类添加附加职责
2.动态的给一个对象添加功能,这些功能可以再动态的撤销。
3.需要为一批的兄弟类进行改装或加装功能。

1.4案例之手抓饼

场景:给我做个手抓饼+鸡蛋+香肠 然后告诉我一共多少钱

1.4.1菜鸟实现法之继承

	首先定义一个煎饼类
	/**煎饼Battercake类
 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class Battercake {
    protected String getMsg(){ return "煎饼";}
    public int getPrice(){ return 5;}

}

创建一个加1个鸡蛋的类

**创建一个加鸡蛋的煎饼 BattercakeWithEgg类
 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class BattercakeWithEgg  extends Battercake{

    @Override
    protected String getMsg() {

        return super.getMsg()+"+1个鸡蛋";
    }

    @Override
    public int getPrice() {
        return super.getPrice()+1;
    }
}

创建一个加1根香肠的类

package my.decorate.shouzhuabingDemo.v1;

/**再创建一个既加鸡蛋又加香肠的BattercakeWithEggAndSausage类:

 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class BattercakeWithEggAndSausage extends BattercakeWithEgg  {
    @Override
    protected String getMsg(){ return super.getMsg() + "+1根香肠";}

    @Override
    //加一个香肠加 2 块钱
    public int getPrice(){ return super.getPrice() + 2;}

}
	

最后生产手抓饼并交对方买单

	package my.decorate.shouzhuabingDemo.v1;

	public class Test {
    public static void main(String[] args) {
        Battercake battercake = new Battercake();
        System.out.println(battercake.getMsg() + ",总价:" + battercake.getPrice());

        BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg();
        System.out.println(battercakeWithEgg.getMsg() + ",总价:" + battercakeWithEgg.getPrice());

        BattercakeWithEggAndSausage battercakeWithEggAndSauage = new BattercakeWithEggAndSausage();
        System.out.println(battercakeWithEggAndSauage.getMsg() + ",总价:" + battercakeWithEggAndSauage.getPrice());
          

    }
}

生成结果
附上uml图
在这里插入图片描述

1.4.1.1思考菜鸟实现法继承会面临的问题

手抓饼会有很多配菜.怎么点(组装) 是顾客决定的.那么 我们怎么做到灵活的给客户生产手抓饼呢?? 如果我需要一个加2个鸡蛋加1根香肠的煎饼 那么用我们现在的类结构是创建不出来的,也无法自动计算出价格,除非再创建一个类做定制。如果需求再变,一直加定制

解决方案:采用装饰器模式

1.4.2老鸟写法:装饰器模式登场

1.将煎饼类抽象化

/**煎饼的抽象类
 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public  abstract class Battercake {

    protected abstract String getMsg();

    protected abstract int getPrice();
}

2.创建一个基本的煎饼(或者叫基础套餐)BaseBattercake:继承Battercake

/**创建一个基本的煎饼(或者叫基础套餐)BaseBattercake:

 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class BaseBattercake extends Battercake {
    @Override
    protected String getMsg(){ return "煎饼";}

    @Override
    public int getPrice(){ return 5;}
}

  1. 创建一个扩展套餐的抽象装饰器BattercakeDecotator类 继承Battercake
/** 创建一个扩展套餐的抽象装饰器BattercakeDecotator类:
 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class BattercakeDecotator extends Battercake
{
    //静态代理,委派
    //(指定抽象类 而不指定BaseBattercake 实体是为了灵活,
    //因为可能以后会有多个类似BaseBattercake 继承了Battercake 的实现类)
    private Battercake battercake;

    public BattercakeDecotator(Battercake battercake) {
        this.battercake = battercake;
    }

    @Override
    protected String getMsg() {
        return  this.battercake.getMsg();
    }

    @Override
    protected int getPrice() {
        return  this.battercake.getPrice();
    }
}

4.鸡蛋装饰器EggDecorator类

package my.decorate.shouzhuabingDemo.v2Decorate;

/** 鸡蛋装饰器EggDecorator类
 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class EggDecorator extends  BattercakeDecotator {
    public EggDecorator(Battercake battercake) {
        super(battercake);
    }

    @Override
    protected String getMsg() {
        return super.getMsg()+ "1个鸡蛋";
    }

    @Override
    protected int getPrice() {
        return super.getPrice()+1;
    }
}

5.香肠类

package my.decorate.shouzhuabingDemo.v2Decorate;

/**
 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class SausageDecorator extends BattercakeDecotator {
    public SausageDecorator(Battercake battercake) {
        super(battercake);
    }

    @Override
    protected String getMsg() {
        return super.getMsg()+ "1根香肠";
    }

    @Override
    protected int getPrice() {
        return super.getPrice()+2;
    }



}

最后生产手抓饼并交对方买单

package my.decorate.shouzhuabingDemo.v2Decorate;

import java.io.InputStream;

/**
 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class Test {

    public static void main(String[] args){
        Battercake  battercake = new BaseBattercake();
        //煎饼有点小,想再加一个鸡蛋
         battercake = new EggDecorator(battercake);
        //再加一个鸡蛋
        battercake = new EggDecorator(battercake);
        //很饿,再加根香肠
        battercake = new SausageDecorator(battercake);

        System.out.println(battercake.getMsg() + ",总价" + battercake.getPrice());
    }
}

在这里插入图片描述
以上就完美实现了灵活加菜加量的功能
场景二:
最近老板瞟了 觉得自己手抓饼生意好.要求大家买手抓饼必须买手抓饼基础套餐(煎饼+可乐) 价格10元 否则不卖

我们只需
创建个必须套餐类 MustBattercake 继承Battercake 重写里面的getMsg

package my.decorate.shouzhuabingDemo.v2Decorate;

/**
 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class MustBattercake extends Battercake {
    @Override
    protected String getMsg() {

        return "煎饼+可乐";
    }

    @Override
    protected int getPrice() {
        return 10;
    }
}

然后test代码
只需要将
换成即可
Battercake battercake = new MustBattercake();

package my.decorate.shouzhuabingDemo.v2Decorate;

import java.io.InputStream;

/**
 * @Description
 * @Author fanjia
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2020/6/11
 */
public class Test {

    public static void main(String[] args){
        Battercake  battercake = new MustBattercake();
        //煎饼有点小,想再加一个鸡蛋
         battercake = new EggDecorator(battercake);
        //再加一个鸡蛋
        battercake = new EggDecorator(battercake);
        //很饿,再加根香肠
        battercake = new SausageDecorator(battercake);

        System.out.println(battercake.getMsg() + ",总价" + battercake.getPrice());
    }
}

在这里插入图片描述

类图
在这里插入图片描述

是不是感觉灵活了很多 符合了开闭原则不需要去修改原来的代码了?

1.5 装饰模式的优缺点

优点:

1、装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用。

2、通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。

3、装饰器完全遵守开闭原则。

缺点:

1、会出现更多的代码,更多的类,增加程序复杂性。

2、动态装饰时,多层装饰时会更复杂。追踪代码更难看点

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值