序
好久没写设计模式了,自从写了两篇之后,就放弃治疗了,主要还是工作太忙了啊(借口,都是借口),过完年以后一直填坑,填了好几个月,总算是稳定下来了,可以打打酱油了。
为什么又重新开始写设计模式呢?学习使我快乐啊(我装逼起来我自己都害怕),其实主要是最近填坑的时候看源代码有点晕,很多代码不知道他们为什么要那么写啊,好气啊
当时第二篇写完,其实就在准备第三篇了,但是,一直也没有写,看了好几遍,但是一直掌握不到精髓(其实现在也掌握不到),感觉挺模糊的,也就一直拖啊拖,拖延症晚期患者已经不用抢救了。。。
先来举个栗子
故事背景:星巴兹咖啡,由于快速扩展,他们现在的订单系统已经跟不上他们的饮料供应需求了,先看一下当前的设计
/**
* 饮料超类
* @author Skysea
*
*/
public abstract class Beverage {
protected String description;//描述
public abstract double cost();//消费金额
public Beverage(String description){
this.description = description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
下面是各种咖啡,这里就只展示一种:
/**
* 首选咖啡
* @author Skysea
*
*/
public class HouseBlend extends Beverage{
public HouseBlend(String description) {
super(description);
}
@Override
public double cost() {
return 3.5;
}
}
很简单的代码,咖啡继承饮料超类。
啥都不说了,先提需求:
1,购买咖啡时,要求可以在其中加入各种调料,例如:蒸奶,豆浆,摩卡...等等(产品每次给我们说的就是,具体的他们还没定好,能不能做成活的?就是随时可以扩展的那种。知道我为啥要来学设计模式了吗?会被玩死的,真的)
2,各种调料也会参与计价,而且每种调料的价格不一定相同
需求清楚了吧?不清楚?没关系,反正下周上线,不存在的,嘿嘿嘿
先来给出第一版实现(直接扩展超类):
/**
* 饮料超类
* @author Skysea
*
*/
public abstract class Beverage {
protected String description;//描述
public abstract double cost();//消费金额
private boolean milk;//牛奶
private boolean soy;//豆浆
private boolean mocha;//摩卡
private boolean whip;//奶泡
//省略get set方法...
}
不就是下周上线吗?不就是要扩展吗?要多少,就在超类里面加就好了啊,然后再对每一种饮料进行处理,像这样:
/**
* 首选咖啡
* @author Skysea
*
*/
public class HouseBlend extends Beverage{
public HouseBlend(String description) {
super(description);
}
@Override
public double cost() {
double cost = 3.5;
if(hasMilk()){
cost += 0.5;
}
if(hasMocha()){
cost += 0.6;
}
if(hasSoy()){
cost += 0.3;
}
if(hasWhip()){
cost += 0.4;
}
return cost;
}
}
感觉每一种都要写这么多if好麻烦啊,不存在的,这种东西,抽出来嘛:
/**
* 饮料超类
* @author Skysea
*
*/
public abstract class Beverage {
/**
* 调料消费
* @return
*/
protected double flavourCost(){
double cost = 0.0;
if(hasMilk()){
cost += 0.5;
}
if(hasMocha()){
cost += 0.6;
}
if(hasSoy()){
cost += 0.3;
}
if(hasWhip()){
cost += 0.4;
}
return cost;
}
//...
}
子类:
/**
* 首选咖啡
* @author Skysea
*
*/
public class HouseBlend extends Beverage{
public HouseBlend(String description) {
super(description);
}
@Override
public double cost() {
return 3.5 + flavourCost();
}
}
感觉也挺好的啊,每次要添加的时候,先去超类添加一个属性,然后在超类的 flavourCost()方法中,添加一段代码,以前的子类完全不用动,逻辑也是妥妥的,一切都是很OK的
但是,这样写至少有三处是不符合逻辑的:
1,所有的子类的cost方法都必须要加上一句 xxx + flavourCost(),不觉得写的次数太多了吗?一般一个方法写N次,那大部分最后会变成坑
2,超类的所有属性并不是每一个子类都能用上的
3,违背了开闭原则,每一次扩展虽然不用修改子类,但是却会去修改父类的属性,以及父类的flavourCost()方法
在现在的这个需求下,这些不合理都是体现不出来有什么问题的,但是,代码中不符合逻辑的东西早晚有一天会对整个模块的设计造成巨大的影响,两种情况除外:
1,你不干了(钱没给够或者我不开心毕竟程序员都是非常任性的),对模块的影响跟你没有半毛钱的关系
2,这个模块不扩展,不维护,或者扩展、维护还没有达到临界点(时间根据前期逻辑混乱程度成反比)
别问我怎么知道的,因为我TM还没走,所以就来学习来了,我擦,跑题了。。。
下面来聊聊刚学的正确姿势:
装饰者模式
先说超类 Beverage(不变,保持最最原始的样子):
/**
* 饮料超类
* @author Skysea
*
*/
public abstract class Beverage {
protected String description;//描述
public abstract double cost();//消费金额
public Beverage(String description){
this.description = description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
th