• 设计模式之装饰者模式


    装饰者模式介绍:动态的将新功能附加到对象上。在对象的功能拓展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(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()主要是递归的形式,遇到具体的主体,递归停止。

  • 相关阅读:
    Happy Number
    [leedcode]Remove Linked List Elements
    [leedcode] Count Primes
    编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 但是要保证汉字不被截半个,如“我ABC”4,应该截为“我AB”,输入“我ABC汉DEF”,6,应该输出为“我ABC”而不是“我ABC+汉的半个”。
    最短路(队列优化)
    两函数的交点
    最小生成树
    最小生成树
    线段树区间修改和查询和单点查询(线段树模板1)
    博弈论合集(博弈)
  • 原文地址:https://www.cnblogs.com/chenmz1995/p/12441581.html
Copyright © 2020-2023  润新知