装饰模式(Decorator Pattern)-(最通俗易懂的案例)

前言

我们通常在编码的时候为了扩展一个类的功能往往用的是继承来实现,但是继承的缺点主要是单继承的局限性和可能产生类爆炸的后果。

装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。装饰模式属于结构型模式,它是作为现有的类的一个包装。

结构模式图

Decorator类图
解析:

  • Component:定义一个对象接口,可以给这些对象动态地添加职责。
  • ConcreteComponent:定义了一个具体的对象,也可以给这个对象添加一些职责。
  • Decorator:装饰抽象类,继承了 Component,从外类来扩展Component的功能,但对于Component来说,是无需知道Decorator的存在的。
  • ConcreteDecoratorA/B:具体的装饰对象,起到给Component添加职责的功能。

案例实现

想想一下这个情景:清晨上班的你在路上遇到一家面馆,你便进去点了一碗面吃,然后你又发现菜单栏上有许多的配料:牛肉、荷包蛋、鸡腿,这时你看到旁边的一个老板把这三个全部点了一遍加到他的面里,于是你也不甘示弱,但作为程序员的你只加了一个荷包蛋进去。
现在我们用装饰模式来完成上面这个需求:往面条里面加配料,上代码:

我们先定义一个对象接口:INoodles

package com.design_pattern.decorator;

/**
 * Created on 2020/3/19
 * Package com.design_pattern.decorator
 *
 * @author dsy
 */
public interface INoodles {
    public void cook();
}

然后写一个具体的实现类:Noodles

package com.design_pattern.decorator;

/**
 * Created on 2020/3/19
 * Package com.design_pattern.decorator
 *
 * @author dsy
 */
public class Noodles implements INoodles {

    @Override
    public void cook() {
        System.out.println("的面条");
    }
}

定义一个抽象装饰类:NoodlesDecorator

package com.design_pattern.decorator;

/**
 * Created on 2020/3/19
 * Package com.design_pattern.decorator
 *
 * @author dsy
 */
public abstract class NoodlesDecorator implements INoodles {

    private INoodles noodles;    //添加一个INoodles 的引用

    public NoodlesDecorator(INoodles noodles){     //通过构造器来设置INoodles 
        this.noodles = noodles;
    }

    @Override
    public void cook() {
        if (noodles!=null){
            noodles.cook();
        }
    }

}

具体装饰类:EggDecorator

package com.design_pattern.decorator;

/**
 * Created on 2020/3/19
 * Package com.design_pattern.decorator
 *
 * @author dsy
 */
public class EggDecorator extends NoodlesDecorator {

    public EggDecorator(INoodles noodles) {
        super(noodles);
    }

    /**
     * 重写父类的cook方法,并添加自己的实现,调用父类的cook方法,此cook方法是通过本类的构造器
     * EggDecorator(INoodles noodles)传入的noodles的cook操作
     */
    @Override
    public void cook() {
        System.out.println("加了一个荷包蛋");
        super.cook();
    }
}


具体装饰类:BeefDecorator

package com.design_pattern.decorator;

/**
 * Created on 2020/3/19
 * Package com.design_pattern.decorator
 *
 * @author dsy
 */
public class BeefDecorator extends NoodlesDecorator {

    public BeefDecorator(INoodles noodles) {
        super(noodles);
    }

    @Override
    public void cook() {
        System.out.println("加了一斤牛肉");
        super.cook();
    }
}

具体装饰类:ChickenLegDecorator

package com.design_pattern.decorator;

/**
 * Created on 2020/3/19
 * Package com.design_pattern.decorator
 *
 * @author dsy
 */
public class ChickenLegDecorator extends NoodlesDecorator {

    public ChickenLegDecorator(INoodles noodles) {
        super(noodles);
    }


    @Override
    public void cook() {
        System.out.println("加了一个鸡腿");
        super.cook();
    }
}

package com.design_pattern.decorator;

/**
 * Created on 2020/3/19
 * Package com.design_pattern.decorator
 *
 * @author dsy
 */
public class Client {

    public static void main(String[] args) {

        //一位老板来了说我全要
        INoodles noodles = new Noodles();
        INoodles noodlesWithEgg = new EggDecorator(noodles);
        INoodles noodlesWithEggAndChickenLeg = new ChickenLegDecorator(noodlesWithEgg);
        INoodles noodlesWithEggAndChickenLegAndBeef = new BeefDecorator(noodlesWithEggAndChickenLeg);
        noodlesWithEggAndChickenLegAndBeef.cook();
        System.out.println("************分割线**************");
        //咱是程序员,咱加一个蛋就行了
        INoodles noodles1 = new Noodles();
        INoodles noodles1WithEgg = new EggDecorator(noodles1);
        noodles1WithEgg.cook();
    }
}

打印输出:

加了一斤牛肉
加了一个鸡腿
加了一个荷包蛋
的面条
************分割线**************
加了一个荷包蛋
的面条

总结

优缺点分析:

优点:

  • 装饰类和被装饰类可以独立发展,不会相互耦合。
  • 装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:

  • 多层装饰比较复杂。

使用场合:

  • 如果你希望在无需修改代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为, 可以使用装饰模式。
  • 如果用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用该模式。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值