zoukankan      html  css  js  c++  java
  • 设计模式之装饰者模式

    装饰者模式介绍:动态的将新功能附加到对象上。在对象的功能拓展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(opc原则)。

     装饰者模式类似于打包一个快递。

    主体(Component):陶瓷、衣服。

    包装(Decorator):报纸填充、塑料泡沫、纸板、木板。

     这边的Component主体一般是抽象的,因为具体的主体肯定是不少的,所以编码中一般是抽象类,具体子类ConcreteComponent继承这个抽象类(如果具体主体的分类超级多,中间可以再加层抽象类作为缓冲层,提取相同的部分)。Decorator也是需要继承主体类并聚合一个主体类。

    以上说法十分抽象,例如有个例子:

    1、咖啡店有很多咖啡总类,Espresso, ShortBlack,LongBlack, Decaf。

    2、调料,milk(牛奶), soy(豆浆), chocolate(巧克力)

    假如我点了一份LongBlack,点了两个巧克力和牛奶作为调料。现在需要用装饰者模式实现订单的组合以计算费用。我们便以上面描述的装饰者模式的思路来用代码实现。

    Drink.java

    public abstract class Drink {
        //描述
        public String des;
        //价格
        private float price = 0.0f;
    
        public String getDes() {
            return des;
        }
    
        public void setDes(String des) {
            this.des = des;
        }
    
        public float getPrice() {
            return price;
        }
    
        public void setPrice(float price) {
            this.price = price;
        }
    
        //计算费用的方法
        public abstract float cost();
    }

    Coffee.java

    public abstract class Coffee extends Drink {
        @Override
        public float cost() {
            return super.getPrice();
        }
    }

    这边的coffee就相当于上面说的缓冲层,因为,drink还分很多种,有果汁、茶、咖啡。 

    LongBlack.java(这个是具体的咖啡)

    public class LongBlack extends Coffee{
        public LongBlack(){
            setDes("LongBlack");
            setPrice(5.0f);
        }
    }

    Decorator.java

    public class Decorator extends Drink {
        private Drink obj;
    
        public Decorator(Drink obj) {
            this.obj = obj;
        }
    
        @Override
        public float cost() {
            //先拿到自己的价格
            return super.getPrice() + obj.cost();
        }
    
        @Override
        public String getDes() {
            //返回自己的信息加被装饰者的信息
            return super.getDes() + " " + super.getPrice() + " && " + obj.getDes();
        }
    }

    Chocolate.java

    public class Chocolate extends Decorator {
    
        public Chocolate(Drink obj) {
            super(obj);
            setDes("巧克力");
            setPrice(3.0f);
        }
        
    }

    Milk.java

    public class Milk extends Decorator {
        public Milk(Drink obj) {
            super(obj);
            setDes("牛奶");
            setPrice(2.0f);
        }
    }

    Client.java

    public class Client {
        public static void main(String[] args) {
            //1、先点一份LongBlack
            Drink order = new LongBlack();
            System.out.println("费用1=" + order.cost());
            System.out.println("描述=" + order.getDes());
    
            //2、加入一份牛奶
            order = new Milk(order);
            System.out.println("order 加入一份牛奶后 费用=" + order.cost());
            System.out.println("描述=" + order.getDes());
    
            //3、加入一份巧克力
            order = new Chocolate(order);
            System.out.println("order 加入一份巧克力后 费用=" + order.cost());
            System.out.println("描述=" + order.getDes());
    
            //4、加入一份巧克力
            order = new Chocolate(order);
            System.out.println("order 加入一份巧克力后 费用=" + order.cost());
            System.out.println("描述=" + order.getDes());
        }
    }

    输出的结果:

    费用1=5.0
    描述=LongBlack
    order 加入一份牛奶后 费用=7.0
    描述=牛奶 2.0 && LongBlack
    order 加入一份巧克力后 费用=10.0
    描述=巧克力 3.0 && 牛奶 2.0 && LongBlack
    order 加入一份巧克力后 费用=13.0
    描述=巧克力 3.0 && 巧克力 3.0 && 牛奶 2.0 && LongBlack

    在代码可以看出来,以上LongBlack(主体)中的getDes()和cost()是直接返回,Decorator实例中的getDes()和cost()主要是递归的形式,遇到具体的主体,递归停止。

  • 相关阅读:
    MySQL常用函数大全讲解
    mysql 获取最近一个月每一天
    Mysql查询某个月的每一天的数据
    Mysql 查询一天中,每个小时数据的数量
    oracle 和 mysql 遍历当前月份每一天
    sql查询总结
    Qt样式表——选择器详解(父子关系,插图详细解释)
    Qt样式表之盒子模型(以QSS来讲解,而不是CSS)
    程序员晋升必备技能——单元测试框架(小豆君的干货铺)
    为什么川普反对中国补贴农业(渐进式发展是非常正确的,如果贸然改动农村土地制度,在城市还不能提供足够的就业岗位下将大量的农民推向城市……请欣赏一下巴西、印度城市的贫民窟)
  • 原文地址:https://www.cnblogs.com/chenmz1995/p/12441581.html
Copyright © 2011-2022 走看看