装饰器模式

2021-05-08  本文已影响0人  知止9528

装饰模式(给对象动态增加新功能,需持有对象实例):装饰模式就是给⼀个对象增加⼀些新的功能,⽽且是动态的,要求装饰对象和被装饰对象实现同⼀个接⼝,装饰对象持有被装饰对象的实例:
使⽤场景:


角色


优缺点

优点

缺点


适用场景


装饰器模式与适配器模式的比较

共同点:都拥有一个目标对象。装饰器通过包装一个装饰对象来扩展其功能,而又不改变其接口,这实际上是基于对象的适配器模式的一种变种。
不同点:适配器模式需要实现另外一个接口,而装饰器模式必须实现该对象的接口。适配器模式主要是为了接口的转换,而装饰者模式关注的是通过组合来动态的为被装饰者注入新的功能或行为(即所谓的责任)。


实现

假设我去买咖啡,首先服务员给我冲了一杯原味咖啡,我希望服务员给我加些牛奶和白糖混合入原味咖啡中。使用装饰器模式就可以解决这个问题。

咖啡接口

定义了获取花费和配料的接口。

/**
 * 咖啡接口
 */
public interface Coffee {
    /**
     * 获取价格
     * @return
     */
    public float getPrice();

    /**
     * 获取咖啡
     * @return
     */
    public String getCoffee();
}

原味咖啡

实现Coffe接口,花费1元,配料中,只有咖啡

/**
 * 原味咖啡类
 */
public class OriginalCoffee implements Coffee {
    @Override
    public float getPrice() {
        return 1;
    }

    @Override
    public String getCoffee() {
        return "原味咖啡";
    }
}

装饰器类

咖啡对象的装饰器类,同样实现Coffee接口,定义一个Coffe对象的引用,在构造器中进行初始化。并且将getPrice()和getCoffee()方法转发给被装饰对象。

/**
 * 咖啡的"装饰器",可以给咖啡添加各种"配料"
 * 该类是一个抽象类需要具体子类来实现
 */
public class DecoratorAbstractCoffee implements Coffee {
    /**
     * 具体咖啡的接口
     */
    protected final  Coffee coffee;

    /**
     * 构造方法,初始化咖啡对象的引用
     * @param coffee
     */
    public DecoratorAbstractCoffee(Coffee coffee) {
        this.coffee = coffee;
    }

    /**
     * 获取价格,装饰器父类中直接转发"请求"至引用对象
     * @return
     */
    @Override
    public float getPrice() {
        return coffee.getPrice();
    }

    /**
     * 获取咖啡,装饰器父类中直接转发"请求"至引用对象
     * @return
     */
    @Override
    public String getCoffee() {
        return coffee.getCoffee();
    }
}

具体的装饰器类

具体的装饰器类,负责往咖啡中“添加”牛奶,注意看getPrice()方法和getCoffee()方法,可以在转发请求之前或者之后,增加功能。如果是代理模式,这里的结构就有所不同,通常代理模式根据运行时的条件来判断是否转发请求。

/**
 * 混合牛奶到蜂蜜中
 */
public class CreamCoffee extends DecoratorAbstractCoffee {
    private float price = (float) 0.5;

    /**
     * 调用父类的构造方法
     * @param coffee
     */
    public CreamCoffee(Coffee coffee) {
        super(coffee);
    }

    /**
     * 增加配料需要加钱
     * @return
     */
    @Override
    public float getPrice() {
        return coffee.getPrice()+price;
    }

    /**
     * 对咖啡进行加工
     * @return
     */
    @Override
    public String getCoffee() {
        return coffee.getCoffee()+";添加牛奶";
    }
}

添加糖

另一个具体装饰器类,用来给咖啡加蜂蜜,一样的逻辑。

class HoneyCoffee extends DecoratorAbstractCoffee {
    private float price = (float) 1.4;

    public HoneyCoffee(Coffee coffee) {
        super(coffee);
    }

    @Override
    public float getPrice() {
        return coffee.getPrice()+price;
    }

    @Override
    public String getCoffee() {
        return coffee.getCoffee()+";添加蜂蜜";
    }
}

客户端使用

public class DecoratorMain {

    public static void main(String[] args) {
        //是不是很像 javaIO中的 stream流
        Coffee coffee = new CreamCoffee(new HoneyCoffee(new OriginalCoffee()));
        System.out.println(coffee.getCoffee());
        System.out.println(coffee.getPrice());

    }
}

总结
装饰器模式是代替增加子类的一种解决方案,体现了聚合/合成复用原则的思想,尽量使用组合的方式来扩展功能,这样就把基本功能和扩展功能解耦了,使得代码可复用,可维护,灵活。关键点在于装饰器模式可以动态地为对象增加扩展功能。

上一篇 下一篇

猜你喜欢

热点阅读