美文网首页Java设计模式
大厂面试必备之设计模式:漫画装饰者模式

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

作者: 天才少年_曹 | 来源:发表于2020-05-17 08:39 被阅读0次





    小安实现的代码如下:

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


    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/wwrjohtx.html