2.装饰者模式----Head First(设计模式进阶)

目标

软件设计目标:正确性、健壮性、灵活性、可重用性、高效性–之后的所有的设计模式,我将会以此来作为学习的落脚点,其实,设计模式就是代码结构的设计技巧,有目标才能知道每种模式出现的根本的原因,和解决掉了什么样的问题.
就以装饰者模式作为开端,打个样出来,之后会不断的完善.

场景

星巴兹咖啡连锁店 ,点咖啡,有多种咖啡,每种咖啡都有标价,名字,
也可以点咖啡加多种调料,调料也有标价和名字,最后的成品的名字是咖啡与调料的组合,价钱是两种的和.我们做出的功能是每种咖啡都可以加不同且多种的调料(灵 活性),可以得到最后的总价和名字,(隐含的要求:可以随时添加新品的咖啡,和调料而不用修改原有的代码(可扩展性))

分析(以下内容如果不好理解可以在看过代码后再看)

咖啡有标价和名字,调料也有标价和名字,可以抽象出基类component,因为点咖啡时可以加多种任意调料,而我们需要得到最终的标价和名字,那么我们怎么才能做到每添加一种调料都可以获得最终的标价和名字呢?如果我们的调料类可以获得上一次添加调料之后的标价和名字的信息,那么我就可以组合添加新的调料的信息,从而得到最终的信息.那么显而易见,调料类的设计应该是包含了component作为属性的,为什么不是包含了调料作为属性呢?因为第一次是将咖啡类组合进来,其他的时候其实是得到的调料类,这也是为什么能用装饰者模式来解决这个问题的关键,咖啡类与调料类有共同的基类(也就是装饰者与被装饰者有共同的基类),并且,该基类的属性和方法正是 该模式传递,修饰数据的通道.

注: 数据传递也就是 数据来源,数据传递通道,数据输出 是软件设计或者是代码设计的基本的组成部分,所有的项目都是这三部分组成,否则,就不是完整的设计.

设计模式正式数据传递通道设计的技巧性总结,或者说是抽象.

下面上代码:

//基础组价抽象类
public  abstract class Component {

    private String name;

    private Float price;

    abstract void operate();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getPrice() {
        return price;
    }

    public void setPrice(Float price) {
        this.price = price;
    }
}
//基础组件实现类(被装饰者)
public class Coffee extends Component {
    @Override
    void operate() {
        setName("coffee");
        setPrice(1f);
    }
}
//装饰者抽象类
public abstract class Flavoring  extends Component{
    //关键技巧 持有基类的实例
    private  Component component;
    @Override
    void operate() {
    //递归截止条件 component==null
        if (component!=null){
           //执行Component的方法
            component.operate();
        }
    }

    public Component getComponent() {
        return component;
    }

    public void setComponent(Component component) {
        this.component = component;
    }
}
//装饰者实现类
public class Tang extends Flavoring {
    @Override
    void operate() {
       //先执行Component的方法,实现了递归,
        super.operate();
        setName("加糖"+getComponent().getName());
        setPrice(getComponent().getPrice()+2);
    }
}
//装饰者实现类
public class Yan extends Flavoring{
    @Override
    void operate() {
        super.operate();
        setName("加盐"+getComponent().getName());
        setPrice(getComponent().getPrice()+1);
    }
}
//测试demo
public class Main {

    public static void main(String [] args){
        Coffee coffee=new Coffee();
        Tang tang=new Tang();
        Yan yan=new Yan();
        //数据传递
        tang.setComponent(coffee);
        yan.setComponent(tang);
        //装饰
        yan.operate();
        System.out.println(tang.getName()+";"+tang.getPrice());
        System.out.println(yan.getName()+";"+yan.getPrice());
    }

}
//输出结果
加糖coffee;3.0
加盐加糖coffee;4.0

从测试demo可以看到上述设计师通过setComponent方法作为装饰的准备,其实就是一层层嵌套,然后通过operate方法,逆向一层层递归,直到Coffee也就是被装饰者,从而实现了根据嵌套的顺序来装饰Coffee的目的.

技巧

主要是使用组合,通过组合的特性来实现装饰准备(setComponent)方法,又因为组合的原因,使我们可以调用component的operate方法实现递归的去装饰被装饰者Coffee.

operate方法设计技巧:

1.必须在基类中声明.

2.在装饰者的基类(Favoring)中的实现逻辑:必须先判断是否为null,这是递归截止的标志,否则会报空指针异常,然后调用component的operate方法,这是实现递归的通道,在装饰者的具体实现类中operate方法必须先调用父类的operate方法,其实就是调用自己持有的component中的operate方法

总结

优点:组合的使用可以更加灵活的添加额外的功能,其实装饰就是额外功能的抽象,装饰者模式通过持有基类的组合技巧,再通过方法的递归调用,实现了特殊的,无数量限制(扩展性),无顺序限制(灵活性),可重复(重用性)装饰效果,可以说是非常的完美了.

不足:当然,结合其他的模式会更加的好用,我们也可以看到被装饰者Coffee的operate实现是写死了的,我们可以通过其他模式更灵活的去实现,还有装饰者的实现类也是同样的问题,那么我们就可以通过其他的模式比如策略模式等

你可能感兴趣的:(设计模式进阶)