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

Posted 天才少年_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大厂面试必备之设计模式:漫画装饰者模式相关的知识,希望对你有一定的参考价值。






小安实现的代码如下:

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







装饰者模式:

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

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

采用策略模式的UML图:

价格抽象类:

/**
 * @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)”文章将在公众号同步发布。

以上是关于大厂面试必备之设计模式:漫画装饰者模式的主要内容,如果未能解决你的问题,请参考以下文章

大厂设计模式面试必备装饰者模式(Decorator Pattern)!

大厂面试必备之设计模式:漫画观察者模式

大厂面试必备之设计模式:漫画适配器模式

大厂面试必备:docker退出容器之后会不会保存

架构师内功心法,有重构项目经验必备的装饰者模式详解

架构师内功心法,有重构项目经验必备的装饰者模式详解