最近在看《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。今天还是有收获的,要不是装饰模式的学习,我一直对面向对象的理解还有错误~