大厂面试必备之设计模式:漫画装饰者模式

大厂面试必备之设计模式:漫画装饰者模式_第1张图片
大厂面试必备之设计模式:漫画装饰者模式_第2张图片
大厂面试必备之设计模式:漫画装饰者模式_第3张图片
大厂面试必备之设计模式:漫画装饰者模式_第4张图片
大厂面试必备之设计模式:漫画装饰者模式_第5张图片
小安实现的代码如下:

/**
 * @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

大厂面试必备之设计模式:漫画装饰者模式_第6张图片
大厂面试必备之设计模式:漫画装饰者模式_第7张图片
大厂面试必备之设计模式:漫画装饰者模式_第8张图片
大厂面试必备之设计模式:漫画装饰者模式_第9张图片
大厂面试必备之设计模式:漫画装饰者模式_第10张图片
大厂面试必备之设计模式:漫画装饰者模式_第11张图片
装饰者模式:

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

官方定义不太好理解,我翻译一下,在装饰者模式中,装饰者和被装饰者继承相同的基类,装饰者可以在要求被装饰者前或者后面加上自己的行为,达到特定的目的。比如青菜价格加在鸳鸯锅底的价格前面,然后再动态的用金针菇价格加在青菜价格前面。

采用策略模式的UML图:
大厂面试必备之设计模式:漫画装饰者模式_第12张图片
价格抽象类:

/**
 * @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自身的价格,达到火锅锅底动态添加配菜,计算总价格的目的。
大厂面试必备之设计模式:漫画装饰者模式_第13张图片
大厂面试必备之设计模式:漫画装饰者模式_第14张图片

/**
 * @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)”文章将在公众号同步发布。
在这里插入图片描述

你可能感兴趣的:(漫画设计模式)