• 设计模式 | 第三篇:装饰者模式


    早上,我去鸡蛋饼小摊拿买了一块鸡蛋饼,加了两煎蛋,加了火腿肠,加了生菜,还加了根油条。

    吃的好饱。。。

    人与动物区别在于,人不仅会吃,而且会思考。所以,这种场景,作为程序员,你应该怎么设计?

    好说!

    /**
     * 反面教材1(BOOM!类爆炸)
     */
    class 鸡蛋饼{
        public double cost() {
            return 3;
        }
    }
    class 鸡蛋饼With鸡蛋 extends 鸡蛋饼{
        public double cost() {
            return super.cost() + 0.5;
        }
    }
    
    class 鸡蛋饼With火腿 extends 鸡蛋饼{
        public double cost() {
            return super.cost() + 1;
        }
    }
    /**
     * 反面教材2(违反开闭原则:类应该对扩展开放,对修改关闭)
     * 以后鸡蛋价格变了,或者加两个鸡蛋,或者再加一种别的调料,想一下你怎么设计?
     */
    
    class 鸡蛋饼2{
        
        /**
         *有鸡蛋
         */
        private boolean hasEgg;
        
        /**
         *有火腿
         */
        private boolean hasHuotui;
        
        public double cost() {
            double basecost =3;
            if(hasEgg) {
                basecost +=0.5;
            }
            if(hasHuotui) {
                basecost +=1;
            }
            
            return basecost;
        }
    
        /**
         * @return the hasEgg
         */
        public boolean isHasEgg() {
            return hasEgg;
        }
    
        /**
         * @param hasEgg the hasEgg to set
         */
        public void setHasEgg(boolean hasEgg) {
            this.hasEgg = hasEgg;
        }
    
        /**
         * @return the hasHuotui
         */
        public boolean isHasHuotui() {
            return hasHuotui;
        }
    
        /**
         * @param hasHuotui the hasHuotui to set
         */
        public void setHasHuotui(boolean hasHuotui) {
            this.hasHuotui = hasHuotui;
        }
    }

    装饰者概念

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

    设计理念

      当我们设计的类不能满足我们的需求的时候,我们可能设计一个类去继承它,但是这样就会使对象之间高度的耦合。

      这时,我们就可以换一种思路,将不能满足我们需求的类A嵌入到要扩展的功能的类B当中。

      这里注意,我们将要扩展的功能设计为一个类B,当这个类构造时可以引入A,B将持有A对象实例。

      这种方法,我们称之为:装饰者模式

    使用场景

      装饰模式的应用在java的I/O流中最为显著。

    设计原则

      对扩展开放,对修改关闭。

    UML类图

     示例

    抽象组件

    package com.study.headfirst.decorator;
    
    /**
     * 抽象组件
     * @author mdl
     * @date 2019/12/05
     */
    public abstract class Pancake {
    
        public String desc = "我不是一个具体的饼";
    
        /**
         * @return the desc
         */
        public String getDesc() {
            return desc;
        }
    
        public abstract double cost();
    
    }

    鸡蛋饼(具体组件A)

    package com.study.headfirst.decorator;
    
    /**
     * @author mdl
     * @date 2019/12/05
     */
    public class TornCake extends Pancake{
        
        public TornCake() {
            desc ="鸡蛋饼";
        }
    
        /* (non-Javadoc)
         * @see com.study.headfirst.decorator.Pancake#cost()
         */
        @Override
        public double cost() {
            // TODO Auto-generated method stub
             return 4;
        }
    
    }

    肉夹馍(具体组件B)

    package com.study.headfirst.decorator;
    
    /**
     * @author mdl
     * @date 2019/12/05
     */
    public class Roujiamo extends Pancake{
        
        public Roujiamo() {
            desc ="肉夹馍";
        }
        
        
        /* (non-Javadoc)
         * @see com.study.headfirst.decorator.Pancake#cost()
         */
        @Override
        public double cost() {
            // TODO Auto-generated method stub
             return 5;
        }
    
    }

    抽象装饰者

    package com.study.headfirst.decorator;
    
    /**
     * 抽象装饰者
     * @author mdl
     * @date 2019/12/05
     */
    public abstract class Condiment extends Pancake{
        
        public abstract String getDesc();
        
    }

    鸡蛋(具体装饰者)

    package com.study.headfirst.decorator;
    
    /**
     * 鸡蛋(具体装饰者)
     * @author mdl
     * @date 2019/12/05
     */
    public class Egg extends Condiment{
        
        private Pancake cake;
        
        public Egg(Pancake cake) {
            this.cake = cake;
        }
        
    
        /* (non-Javadoc)
         * @see com.study.headfirst.decorator.Condiment#desc()
         */
        @Override
        public String getDesc() {
            // TODO Auto-generated method stub
             return cake.getDesc() + ",鸡蛋";
        }
    
        /* (non-Javadoc)
         * @see com.study.headfirst.decorator.Pancake#cost()
         */
        @Override
        public double cost() {
            // TODO Auto-generated method stub
             return cake.cost() + 1;
        }
    
    }

    火腿(具体装饰者)

    package com.study.headfirst.decorator;
    
    /**
     * 火腿(具体装饰者)
     * @author mdl
     * @date 2019/12/05
     */
    public class Ham extends Condiment{
    
        private Pancake cake;
        
        public Ham(Pancake cake) {
            this.cake = cake;
        }
        
        /* (non-Javadoc)
         * @see com.study.headfirst.decorator.Condiment#desc()
         */
        @Override
        public String getDesc() {
            // TODO Auto-generated method stub
             return cake.getDesc() + ", 火腿";
        }
    
        /* (non-Javadoc)
         * @see com.study.headfirst.decorator.Pancake#cost()
         */
        @Override
        public double cost() {
            // TODO Auto-generated method stub
             return cake.cost() + 1.5;
        }
    
    }
    View Code

    生菜(具体装饰者)

    package com.study.headfirst.decorator;
    
    /**
     * 生菜(具体装饰者)
     * @author mdl
     * @date 2019/12/05
     */
    public class ShenCai extends Condiment{
        
        private Pancake cake;
        
        public ShenCai(Pancake cake) {
            this.cake = cake;
        }
    
        /* (non-Javadoc)
         * @see com.study.headfirst.decorator.Condiment#desc()
         */
        @Override
        public String getDesc() {
            // TODO Auto-generated method stub
             return cake.getDesc() + ", 生菜";
        }
    
        /* (non-Javadoc)
         * @see com.study.headfirst.decorator.Pancake#cost()
         */
        @Override
        public double cost() {
            // TODO Auto-generated method stub
             return cake.cost() + 0.5;
        }
    
    }
    View Code

    测试

    package com.study.headfirst.decorator;
    
    /**
     * @author mdl
     * @date 2019/12/05
     */
    public class Test {
    
        public static void main(String[] args) {
            // 点个鸡蛋饼,啥都不加
            Pancake cake =new TornCake();
            System.out.println(cake.getDesc() + ",价钱:" + cake.cost());
            
            // 点个鸡蛋饼,加两根火腿,加生菜
            Pancake cake2 =new TornCake();
            cake2 =new Ham(cake2);
            cake2 =new Ham(cake2);
            cake2 =new ShenCai(cake2);
            System.out.println(cake2.getDesc() + ",价钱:" + cake2.cost());
        }
        
    }

    每一步脚印都要扎得深一点!
  • 相关阅读:
    flask总结02
    flask总结01
    恩智浦Freescale Cortex-A9 迅为IMX6开发板平台初体验
    [分享] IMX6嵌入式开发板linux QT挂载U盘及TF卡
    迅为4412嵌入式安卓开发板兼容3G网络|4G网络
    迅为嵌入式4412平台兼容3G/4G模块的安卓开发板
    飞思卡尔开发板-迅为IMX6开兼容单核 双核 四核Plus开发板
    物联网初学者智能家居必备迅为iTOP-4412开发板
    【分享】4412开发板POP烧写ubuntu出错,如何挂载emmc分区解决方法
    [安卓开发板]迅为IMX6 四核Android开发板
  • 原文地址:https://www.cnblogs.com/bloodthirsty/p/12011024.html
Copyright © 2020-2023  润新知