/**
* @Author: 欢迎关注公众号:程序员小安
* @description:价格基类
* 配菜通过成员变量动态设置
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public abstract class Price {
private boolean isNeedVegetables;//是否要青菜
private boolean isNeedFlammulinaVelutipes;//是否需要金针菇
private boolean isNeedDuckBlood;//是否需要鸭血
private boolean isNeedSprouts;//是否需要豆芽
/**
* 获取价格
* @return
*/
public double getPrice(){
double totalPrice = 0.0;
if(isNeedVegetables()){
totalPrice += 8.9;
}
if(isNeedFlammulinaVelutipes()){
totalPrice += 6.9;
}
if(isNeedDuckBlood()){
totalPrice += 11.9;
}
if(isNeedSprouts()){
totalPrice += 4.9;
}
return totalPrice;
}
public boolean isNeedVegetables() {
return isNeedVegetables;
}
public void setNeedVegetables(boolean needVegetables) {
isNeedVegetables = needVegetables;
}
public boolean isNeedFlammulinaVelutipes() {
return isNeedFlammulinaVelutipes;
}
public void setNeedFlammulinaVelutipes(boolean needFlammulinaVelutipes) {
isNeedFlammulinaVelutipes = needFlammulinaVelutipes;
}
public boolean isNeedDuckBlood() {
return isNeedDuckBlood;
}
public void setNeedDuckBlood(boolean needDuckBlood) {
isNeedDuckBlood = needDuckBlood;
}
public boolean isNeedSprouts() {
return isNeedSprouts;
}
public void setNeedSprouts(boolean needSprouts) {
isNeedSprouts = needSprouts;
}
}
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:鸳鸯锅底
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class MandarinDuckPrice extends Price {
@Override
public double getPrice() {
return 88.0+ super.getPrice();
}
}
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:骨头汤锅底
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class BonepPrice extends Price {
@Override
public double getPrice() {
return 68.0 + super.getPrice();
}
}
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:四格锅底
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class FourGridPrice extends Price {
@Override
public double getPrice() {
return 118.0 + super.getPrice();
}
}
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:用户点餐类
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class User {
public static void main(String[] args){
MandarinDuckPrice mandarinDuckPrice = new MandarinDuckPrice();//用户选中鸳鸯锅底
mandarinDuckPrice.setNeedVegetables(true);//用户需要青菜
mandarinDuckPrice.setNeedFlammulinaVelutipes(true);//用户需要金针菇
System.out.println("您需要支付金额为:"+mandarinDuckPrice.getPrice());//输出总金额
}
}
运行结果:
您需要支付金额为:103.8
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
官方定义不太好理解,我翻译一下,在装饰者模式中,装饰者和被装饰者继承相同的基类,装饰者可以在要求被装饰者前或者后面加上自己的行为,达到特定的目的。比如青菜价格加在鸳鸯锅底的价格前面,然后再动态的用金针菇价格加在青菜价格前面。
/**
* @Author: 欢迎关注公众号:程序员小安
* @description: 价格抽象类
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public abstract class Price {
/**
* 获取价格
* @return
*/
public abstract double getPrice();
}
被装饰者:
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:鸳鸯锅底(具体被装饰者类)
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class MandarinDuckPrice extends Price {
@Override
public double getPrice() {
return 88.0;
}
}
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:四格锅底(具体被装饰者类)
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class FourGridPrice extends Price {
@Override
public double getPrice() {
return 118.0;
}
}
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:骨头汤锅底(具体被装饰者类)
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class BonepPrice extends Price {
@Override
public double getPrice() {
return 68.0;
}
}
装饰者:
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:青菜价格(具体装饰者类)
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class Vegetables extends Price {
private Price price;
public Vegetables(Price price) {
this.price = price;
}
@Override
public double getPrice() {
return 8.9 + price.getPrice();
}
}
/**
* @Author: 欢迎关注公众号:程序员小安
* @description: 豆芽价格(具体装饰者类)
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class Sprouts extends Price {
private Price price;
public Sprouts(Price price) {
this.price = price;
}
@Override
public double getPrice() {
return 4.9 + price.getPrice();
}
}
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:金针菇价格(具体装饰者类)
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class FlammulinaVelutipes extends Price {
private Price price;
public FlammulinaVelutipes(Price price) {
this.price = price;
}
@Override
public double getPrice() {
return 6.9 + price.getPrice();
}
}
/**
* @Author: 欢迎关注公众号:程序员小安
* @description: 鸭血价格(具体装饰者类)
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class DuckBlood extends Price {
private Price price;
public DuckBlood(Price price) {
this.price = price;
}
@Override
public double getPrice() {
return 11.9 + price.getPrice();
}
}
用户点餐类:
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:用户点餐类
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class User {
public static void main(String[] args){
Price mandarinDuckPrice = new MandarinDuckPrice();//用户选中鸳鸯锅底
mandarinDuckPrice = new Vegetables(mandarinDuckPrice);//用户需要青菜,用Vegetables装饰mandarinDuckPrice
mandarinDuckPrice = new FlammulinaVelutipes(mandarinDuckPrice);//用户需要金针菇,FlammulinaVelutipes装饰mandarinDuckPrice
System.out.println("您需要支付金额为:"+mandarinDuckPrice.getPrice());//输出总金额
}
}
运行结果:
您需要支付金额为:103.8
采用装饰者模式后,可以动态的用一个或者多个装饰者装饰对象,比如上面user类中,用DuckBlood,FlammulinaVelutipes装饰MandarinDuckPrice对象。在装饰者内部,比如DuckBlood的getPrice()方法中,我们可以在被装饰对象Price的getPrice()方法前加上DuckBlood自身的价格,达到火锅锅底动态添加配菜,计算总价格的目的。
/**
* @Author: 欢迎关注公众号:程序员小安
* @description:用户点餐类
* @CreateDate: 2020/3/6
* @Version: 1.0
*/
public class User {
public static void main(String[] args){
Price mandarinDuckPrice = new MandarinDuckPrice();//用户选中鸳鸯锅底
mandarinDuckPrice = new Vegetables(mandarinDuckPrice);//用户需要青菜,用Vegetables装饰mandarinDuckPrice
mandarinDuckPrice= new Vegetables(mandarinDuckPrice);//用户需要青菜,用Vegetables装饰mandarinDuckPrice
mandarinDuckPrice = new FlammulinaVelutipes(mandarinDuckPrice);//用户需要金针菇,FlammulinaVelutipes装饰mandarinDuckPrice
System.out.println("您需要支付金额为:"+mandarinDuckPrice.getPrice());//输出总金额
}
}
运行结果:
您需要支付金额为:112.7
装饰者模式的优点
(1)装饰模式可以提供比继承更多地灵活性。
(2)可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
(3)通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
(4)具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
策略模式的缺点
(1)会产生很多的小对象(具体装饰类),增加了系统的复杂性。
(2)这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
什么时候使用:
某些业务中,需要动态扩展一个类的行为时优先考虑装饰者模式,因为继承是静态的,无法满足。
微信搜索【程序员小安】“面试系列(java&andriod)”文章将在公众号同步发布。