给对象增强的手段
1、继承
- 被增强的对象是固定的
- 增强的内容也是固定的
2、装饰者模式 - 被增强的对象是可以切换的
- 增强的内容是固定的
3、动态代理 - 被增强的内容是可以切换的
- 增强的内容也可以切换
星巴兹公司原先的代码
image.png
新的需求:购买咖啡时,可以要求在其中加入任何调料,例如:奶茶,牛奶,豆浆。星巴兹根据业务需求会计算相应的费用。这就要求订单系统必须考虑到这些调料的部分。
第一个设计.png这里设计非常繁琐:比如要算一杯 HouseBlend的价格,总共就以下几个类
HouseBlend&&奶茶
HouseBlend&&牛奶
HouseBlend&&豆浆
...等等
这样设计需要算出每一种咖啡和配料的组合的可能,类的创建非常之多。而且增加一种调料增加的类也是非常爆炸的。
第二个设计.png这里可以看出继承的局限性,只能增强一个对象。
package com.yl;
public class Beverage {
protected String description;//饮料简介
protected boolean milk=false;//是否有牛奶
protected boolean soy=false;//是否有豆浆
protected boolean cocha=false;//是否有摩卡
protected boolean whip=false;//是否有奶泡
protected double milkCost=1.01;//牛奶价格
protected double soyCost=1.03;//豆浆价格
protected double cochaCost=2.23;//摩卡价格
protected double whipCost=0.89;//奶泡价格
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean hasMilk() {
return milk;
}
public void setMilk(boolean milk) {
this.milk = milk;
}
public boolean hasSoy() {
return soy;
}
public void setSoy(boolean soy) {
this.soy = soy;
}
public boolean hasCocha() {
return cocha;
}
public void setCocha(boolean cocha) {
this.cocha = cocha;
}
public boolean hasWhip() {
return whip;
}
public void setWhip(boolean whip) {
this.whip = whip;
}
public double getCochaCost() {
return cochaCost;
}
public void setCochaCost(double cochaCost) {
this.cochaCost = cochaCost;
}
public double getWhipCost() {
return whipCost;
}
public void setWhipCost(double whipCost) {
this.whipCost = whipCost;
}
/**
* 计算调料价格
* @return
*/
public double cost(){
double condiments=0.0;
if(hasMilk()){//是否需要牛奶
condiments+=milkCost;
}
if(hasSoy()){//是否需要豆浆
condiments+=soyCost;
}
if(hasCocha()){//是否需要摩卡
condiments+=cochaCost;
}
if(hasWhip()){//是否需要奶泡
condiments+=whipCost;
}
return condiments;
}
}
public class DarkRoast extends Beverage {
public DarkRoast(){
description="Most Excellent Dark Roast!";
}
public double cost(){
return 1.99+super.cost();
}
}
这样会存在几个问题:
1、增加调料或者减少调料或者价格变化,都需要该基类Beverage的代码。违反了开放-关闭原则。一旦基类经过测试上线基本是不能修改的,因为影响到了太多的子类。
2、如果加两分调料也是没办法计算价格的。
使用装饰者模式
public abstract class Beverage {
protected String description="Unknown";//饮料简介
/**
* 计算价格
* @return
*/
public abstract double cost();
public String getDescription() {
return description;
}
}
public class DarkRoast extends Beverage {
public DarkRoast(){
description="Most Excellent Dark Roast!";
}
public double cost(){
return 1.99;
}
}
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
/**
* 牛奶装饰类
* @author user
*
*/
public class Milk extends CondimentDecorator {
private Beverage beverage;
public Milk(Beverage beverage) {
this.beverage=beverage;
}
@Override
public String getDescription() {
return beverage.getDescription()+",milk";
}
@Override
public double cost() {
return beverage.cost()+0.2;
}
}
/**
* 奶泡装饰类
* @author user
*
*/
public class Whip extends CondimentDecorator {
private Beverage beverage;
public Whip(Beverage beverage) {
this.beverage=beverage;
}
@Override
public String getDescription() {
return beverage.getDescription()+",Whip";
}
@Override
public double cost() {
return beverage.cost()+0.5;
}
}
装饰者模式的缺点:
1、如果代码中有针对类型的对象类型做一些事情,会失败。包装类虽然具有被包装类的所有属性和方法,但是类型变了。
Beverage beverage=new DarkRoast();// 1.99
beverage=new Milk(beverage);// 0.2
beverage=new Milk(beverage);// 0.2
beverage=new Whip(beverage);// 0.5
System.out.println(beverage.getDescription()+":"+beverage.cost());
if(beverage instanceof DarkRoast) {
System.out.println("打八折:"+beverage.cost()*0.8);
}
2、java io流当中就使用了大量的装饰者模式,但是会发现生成了大量的小类,使得代码复杂度变高。
网友评论