关于装饰模式

        最近在看《Head First》这本书来学习设计模式,正确说是:面向对象设计模式,在看到装饰模式这一章的时候发现了一个问题,也说明我对面向对象编程还不够完全,所以今天打算写一篇文章来记录一下。不过为什么这篇文章我将它放在了技术闲扯的分类里,而没有开一个新的设计模式分类呢?原因是我并不打算系统性的去讲关于设计模式的东西,因为网上已经太多了,即使将来我打算开一个新的设计模式分类,我只会写一些个人的理解,因为关于设计模式的文章实在太多,也肯定比我写的好。
        言归正传,先把用到的几个类列一下,首先按照书中来说有一个抽象饮料类:Beverage

public abstract class Beverage {
    protected String description = "Unknown Beverage";
    protected double price;

    public String getDescription(){
        return description;
    }

    public abstract double cost();
}
然后是用来“装饰”饮料的抽象类:CondimentDecorator ,这里针对饮料来理解装饰一词就是各种 添加料,比如摩卡,豆浆,奶泡等

public abstract class CondimentDecorator extends Beverage {
    protected Beverage beverage;
    public abstract String getDescription();
}
在下面是饮料的一个实现类:Espresso

public class Espresso extends Beverage {
    public Espresso() {
        price = 1.99;
        description = "Espresso";
    }
    @Override
    public double cost() {
        return price;
    }
}
装饰的实现类之一:Mocha

public class Mocha extends  CondimentDecorator {
    public Mocha(Beverage beverage){
        this.price = 0.20;
        this.beverage = beverage;
    }
    @Override
    public String getDescription() {
        return beverage.getDescription() + ",Mocha";
    }
    @Override
    public double cost() {
        return beverage.cost() + price;
    }
}
装修的实现类之二:Whip

public class Whip extends CondimentDecorator {
    public Whip(Beverage beverage){
        this.price = 0.10;
        this.beverage = beverage;
    }
    @Override
    public double cost() {
        return beverage.cost()+price;
    }
    @Override
    public String getDescription() {
        return beverage.getDescription()+",Whip";
    }
}
下面关键的测试类来了

public class TestDecorator {
    public static void main(String[] args) {
        Beverage b1 = new Espresso();
        b1 = new Mocha(b1);
        b1 = new Whip(b1);
        System.out.println(b1.getDescription() + ":" + b1.cost());

        Beverage b2 = new Espresso();
        b2 = new Mocha(b2);
        b2 = new Whip(b2);
        b2 = new Whip(b2);
        System.out.println(b2.getDescription() + ":" + b2.cost());
    }
}
        我的问题就出在这,原先我一直以为创建了Espresso传给b1,而后又创建了Mocha和Whip依然传给b1 那么b1最后存着的应该是最后那个Whip的对象,所以最后调用cost的时候应该调用的是Whip类的cost方法,答案是2.09,但是最终的结果却是先调用了Espresso的cost再累加Mocha的,然后再调用Whip的逐步累加出的,正确答案是2.29。说明一直以来我的理解都有偏差,但是最后我想明白了,原因是这样:new 每次都会创建一个新的对象,那么就会分配一块新内存,在一开始b1指向了Espresso这个内存的引用,而后创建Mocha的时候将自身的饮用传进Mocha的构造方法,那么Mocha里的beverage变量就存有原先的b1的饮用,然后b1又存了新new出来的Mocha对象的引用,以此类推,那么最终b1存着的是新new 出来的 Whip对象的饮用,而Whip又存有原来指向Mocha那个对象的饮用,所以最终调用b1的cost方法时,里面的beverage是原来的Mocha对象的引用,那么当然先调它的cost方法,然后Mocha对象的引用里的beverage又指向最初的Espresso,最终的执行就变成了先调Espresso的cost,再调Mocha的,再调Whip的,所以最后的cost是累加出来的价格,答案是2.29。今天还是有收获的,要不是装饰模式的学习,我一直对面向对象的理解还有错误~

 

fantasycoding.net 2016-2024 © All rights Reserved京ICP备2020039454号-1