34

设计模式-装饰器模式 - 公众号JavaStorm - 博客园

 4 years ago
source link: https://www.cnblogs.com/uniqueDong/p/10993186.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

微信关注公众号 JavaStorm 获取最新内容。

装饰器模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活;它允许向一个现有的对象添加新的功能,同时又不改变其结构。装饰器模式属于结构型模式。

UML 类图

装饰器模式
  • Component:接口,定义一个抽象接口装饰对象与真实对象具有相同的接口,以便装饰器动态的添加职责。
  • ConcreteComponent: 接口的具体对象。
  • Decorator:装饰类,继承了 Component , 从外类来拓展 Component 的功能 并且持有一个 Component 的引用,通过构造器实例化,从而实现对真实对象的职责装饰增强。
  • ConcreteDecorator:具体装饰类,用于给实际对象添加职责。

现在有一个场景:煎饼果子,科技园上班族早上去买煎饼果子(Pancake),有的人要加鸡蛋 (Egg)、有的人加火腿 (Ham)、有的人加生菜 (Lettuce)。有的土豪煎饼果子来一套全都要。现在我们来定义煎饼烹饪实现。(ps:留一个功能读者自己实现:不同的套餐价格是不一样的,如何计算出不同煎饼果子的价格?有兴趣的读者可以留言或者微信公众号后台留言)。

代码可以左右滑动

  1. 先定义煎饼接口也就是我们的被装饰类,以及烹饪的方法 。
package com.zero.headfirst.decorator;

public interface Pancake {
    /**
     * 烹饪方法
     */
    void cook();
}
  1. 定义一个乞丐版煎饼,被装饰对象。
package com.zero.headfirst.decorator;

/**
 * 被装饰对象:定义最基本的乞丐版煎饼,啥都没加
 */
public class BeggarPancake implements Pancake {
    @Override
    public void cook() {
        System.out.println("乞丐版基本煎饼");
    }
}
  1. 定义抽象装饰类 煎饼果子装饰器 PancakeDecorator:抽象装饰器角色,实现煎饼接口(被装饰器接口),持有被装饰器的引用 (pancake)将烹饪行为转发具体的装饰器。
package com.zero.headfirst.decorator;

/**
 * 抽象装饰器角色,实现煎饼接口(被装饰器接口),持有被装饰器的引用将烹饪行为转发具体的装饰器。
 */
public abstract class PancakeDecorator implements Pancake {

    private Pancake pancake;

    public PancakeDecorator(Pancake pancake) {
        this.pancake = pancake;
    }

    @Override
    public void cook() {
        if (pancake != null) {
            pancake.cook();
        }
    }
}
  1. 各种具体装饰类对乞丐版煎饼进行不等级别的土豪加工。首先继承 抽象出来的 PancakeDecorator ,重写 cook 方法,实现加工。

EggDecorator 鸡蛋装饰器:继承 PancakeDecorator,重写 cook 方法。动态添加鸡蛋,然后调用pancake 的cook。

package com.zero.headfirst.decorator;

/**
 * 鸡蛋装饰器:覆盖cook方法,加入自身的实现,并且调用父类的cook方法,也就是构造函数中
 * EggDecorator(Pancake pancake),这里传入的pancake的cook操作
 */
public class EggDecorator extends PancakeDecorator {
    public EggDecorator(Pancake pancake) {
        super(pancake);
    }

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

火腿装饰器: HamDecorator

package com.zero.headfirst.decorator;

/**
 * 火腿装饰器
 */
public class HamDecorator extends PancakeDecorator {

    public HamDecorator(Pancake pancake) {
        super(pancake);
    }

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

}

生菜装饰器

package com.zero.headfirst.decorator;

/**
 * 生菜装饰器
 */
public class LettuceDecorator extends PancakeDecorator {

    public LettuceDecorator(Pancake pancake) {
        super(pancake);
    }

    @Override
    public void cook() {
        System.out.println("加生菜;");
        super.cook();
    }

}

  1. 定义一个煎饼果子摊位。
package com.zero.headfirst.decorator;

/**
 * 煎饼果子店
 */
public class PancakeShop {
    public static void main(String[] args) {
        System.out.println("========土豪来了,全都加上。======");
        BeggarPancake beggarPancake = new BeggarPancake();
        EggDecorator eggDecorator = new EggDecorator(beggarPancake);
        HamDecorator hamAndEggDecorator = new HamDecorator(eggDecorator);
        LettuceDecorator lettuceAndHamAndEggDecorator = new LettuceDecorator(hamAndEggDecorator);
        lettuceAndHamAndEggDecorator.cook();

        System.out.println("========苦逼码农来了,只要鸡蛋补补脑。=====");
        BeggarPancake beggarPancake1 = new BeggarPancake();
        EggDecorator eggDecorator1 = new EggDecorator(beggarPancake1);
        eggDecorator1.cook();
    }
}

========土豪来了,全都加上。======

加生菜;

加一个火腿;

加一个鸡蛋;

乞丐版基本煎饼

========苦逼码农来了,只要鸡蛋补补脑。=====

加一个鸡蛋;

乞丐版基本煎饼

真实世界的装饰: Java I/O。
注意事项与要点

  • 抽象装饰器与具体被装饰对象实现同一个接口。
  • 抽象装饰器持有被装饰器接口对象,以便请求传递。
  • 具体装饰器需要重写抽象装饰器的方法并引用super进行条用,转发请求。
  • 拓展一个类的功能。

  • 动态的添加与撤销职责。

  • 装饰类与被装饰类只关心自己的核心逻辑,实现了解耦。
  • 方便动态拓展,开闭原则。且比继承灵活。
  • 如果功能拓展太多,将产生大量的类。
  • 多层装饰会变得复杂。

以上代码可参考我的 GitHub : https://github.com/UniqueDong/zero-design-stu。headfirst包下。欢迎关注公众号: JavaStorm 获取最新文章,也可在后台留言提出意见。收藏与关注是最大的鼓励。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK