Java设计模式-装饰器模式

设计模式之装饰器模式

装饰器模式是一种结构型设计模式,可以做到在不改变原来对象功能的情况下,向原有的对象添加新的功能,起到一个装饰的作用。具体的做法是创建一个装饰器类,用来包装原有的类,在不改变原有类方法的情况下,为原有类添加新的功能。


来看一个例子,我们在外面吃饭,有很多食物,其中有烧烤和火锅。比如我们点了烧烤,但是觉得味道不够爽,所以我们选择让老板加盐,或者加辣椒,这里的加盐和加辣椒其实就是对事物起装饰作用。用代码实现如下:

创建Food接口

提供两个抽象方法

public interface Food {
    /**
     * 返回描述
     * @return
     */
    String getDesc();

    /**
     * 返回价格
     * @return
     */
    String getCost();
}

创建实现接口的实现类

Barbecue实现类

public class BarbecueFood implements Food {
    /**
     * 返回描述
     *
     * @return
     */
    @Override
    public String getDesc() {
        return "烧烤";
    }

    /**
     * 返回价格
     *
     * @return
     */
    @Override
    public String getCost() {
        Double cost = 3.0;
        return String.format("最后价格:%s块", cost);
    }
}

Hotpot实现类

public class HotpotFood implements Food {
    /**
     * 返回描述
     *
     * @return
     */
    @Override
    public String getDesc() {
        return "火锅";
    }

    /**
     * 返回价格
     *
     * @return
     */
    @Override
    public String getCost() {
        Double cost = 100.0;
        return String.format("最后价格:%s块", cost);
    }
}

创建装饰器基类

FoodDecorator是一个抽象类,其中组合Food类

public abstract class FoodDecorator implements Food {
    protected Food food;

    public FoodDecorator(Food food) {
        this.food = food;
    }

    /**
     * 返回描述
     *
     * @return
     */
    @Override
    public String getDesc() {
        return food.getDesc();
    }

    /**
     * 返回价格
     *
     * @return
     */
    @Override
    public String getCost() {
        return food.getCost();
    }
}

创建SaltFoodDecorator装饰器类


public class SaltFoodDecorator extends FoodDecorator {

    public SaltFoodDecorator(Food food) {
        super(food);
    }

    /**
     * 返回描述
     *
     * @return
     */
    @Override
    public String getDesc() {
        String result = "加盐的" + food.getDesc();

        return result;
    }

    /**
     * 返回价格
     *
     * @return
     */
    @Override
    public String getCost() {
        Double salt = 2.0;
        System.out.println(String.format("加盐多收%s块", salt));
        String result = food.getCost() + " + " + salt + "块";

        return result;
    }
}

创建PepperFoodDecorator装饰器类

public class PepperFoodDecorator extends FoodDecorator {

    public PepperFoodDecorator(Food food) {
        super(food);
    }

    /**
     * 返回描述
     *
     * @return
     */
    @Override
    public String getDesc() {
        String result = "加盐的" + food.getDesc();

        return result;
    }

    /**
     * 返回价格
     *
     * @return
     */
    @Override
    public String getCost() {
        Double pepper = 10.0;
        System.out.println(String.format("加辣椒多收%s块", pepper));
        String result = food.getCost() + " + " + pepper + "块";

        return result;
    }
}

最后来测试一下

public class Main {
    public static void main(String[] args) {
        //创建不用装饰器修饰的Food
        Food food = new BarbecueFood();
        display(food.getDesc());
        display(food.getCost());
        System.out.println("-------------分割线---------------");
        //创建用SaltFoodDecorator装饰的Food
        Food barbecue = new SaltFoodDecorator(new BarbecueFood());
        display(barbecue.getDesc());
        display(barbecue.getCost());
        System.out.println("-------------分割线---------------");
        //创建用PepperFoodDecorator装饰的Food
        Food hotSpot = new PepperFoodDecorator(new HotpotFood());
        display(hotSpot.getDesc());
        display(hotSpot.getCost());
    }

    private static void display(Object obj) {
        System.out.println(obj);
    }

}

结果如下:

烧烤
最后价格:3.0-------------分割线---------------
加盐的烧烤
加盐多收2.0块
最后价格:3.0+ 2.0-------------分割线---------------
加盐的火锅
加辣椒多收10.0块
最后价格:100.0+ 10.0

来看一下类图会更加地清晰

END

装饰器模式在日常开发中也有很多应用,典型的就是JDK里面的IO。

InputStream代表输入流,输入来源可以是文件(FileInputStream)、管道(PipedInputStream)、数组(ByteArrayInputStream)等。就像上面的烧烤,火锅。FilterInputStream就是装饰器的基类,他的实现类是一系列的装饰器,比如BufferedInputStream可以用缓冲区来修饰InputStream,把InputSteam包装成有缓冲区的输入流。


   转载规则

本文不允许转载。
 上一篇
使用Docker容器化SpringBoot+Dubbo应用的实践 使用Docker容器化SpringBoot+Dubbo应用的实践
使用Docker容器化SpringBoot+Dubbo应用的实践Docker在日常开发中越来越火,工作中后端很多项目都需要使用Docker进行容器化,SpringBoot+Docker被称为“原生云应用”,SpringBoot应用和D
2018-06-10
下一篇 
Java并发之多线程 Java并发之多线程
Java并发之多线程什么是线程? 通常我们在使用桌面操作系统的时候,说的都是XXX进程。比如我们启动一个Java程序,那操作系统中就会新建一个Java进程。那线程是什么呢?线程是比进程更加轻量级的调度单位,在现代操作系统中,线程就是最小的调
  目录