• 23种设计模式之装饰者模式


    装饰者模式:动态的将新功能(装饰者,如调料)附加到对象(主体,如单品咖啡)上。在对象功能扩展方面,它比继承更有弹性。

    1、以咖啡馆订单系统项目为例

    咖啡种类:Espresso、ShortBlack、LongBlack、Decaf

    调料:Milk、Soy、Chocolate

    咖啡可以点单品,也可以和任意调料混合,最后返回咖啡价格

    一个差的方案,为每一个单品和单品与调料组合,创建类,如Espresso类、ShortBlack类、Espresso&Milk类、Espresso&Milk&Soy类等,每个类里返回咖啡价格,这种方案导致类爆炸

    稍微好点但是也不好的方案是,设计一个抽象超类,把调料内置到超类中,可设置添加调料方法,在单品继承自超类的实现类里,通过判断是否设置有某种调料,再计算价钱,这种设计太繁琐,而且不易扩展,如要新增一种调料,那就要改动代码,容易出错

    2、装饰者模式设计:

    装饰者设计模式是通过递归方式调用对象方法的,装饰者要继承自抽象主体,并且会调用抽象主体的方法,装饰者是依附于主体的

    形如new Chocolate(new Chocolate(new Milk(new LongBlack))),如果返回价格调用cost方法,由于装饰者(调料)也继承自主体(Drink),而且调料.cost方法中会调用drink中的cost,一直递归调用到单品的cost方法

    3、装饰者模式代码示例

    //主体类
    public abstract class Drink {
    
        private String description = "";
        private float price = 0f;
    
        public String getDescription() {
            return description + "-" + this.price;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
        public float getPrice() {
            return price;
        }
    
        public void setPrice(float price) {
            this.price = price;
        }
    
        //单品中返回价格,调料中要加上单品价格
        public abstract float cost();
    }
    抽象主体Drink 有description和price属性来定义继承自主体的单品描述和价格,抽象方法cost用来计算单品或混合咖啡总消费
    //主体中间层
    public class Coffee extends Drink {
        public float cost() {
            return super.getPrice();
        }
    }
    设置中间层Coffee extends Drink,所有单品都继承自Coffee,单品的消费就是单品的价格
    public class Decaf extends Coffee {
    
        public Decaf() {
            super.setDescription("Decaf");
            super.setPrice(3.0f);
        }
    
    }
    Decaf extends Coffee单品构造中初始化描述及价格
    public class Espresso extends Coffee {
    
        public Espresso() {
            super.setDescription("Espresso");
            super.setPrice(4.0f);
        }
    
    }
    Espresso extends Coffee单品构造中初始化描述及价格
    public class LongBlack extends Coffee {
    
        public LongBlack() {
            super.setDescription("LongBlack");
            super.setPrice(5.0f);
        }
    
    }
    LongBlack extends Coffee单品构造中初始化描述及价格
    public class ShortBlack extends Coffee {
    
        public ShortBlack() {
            super.setDescription("ShortBlack");
            super.setPrice(6.0f);
        }
    
    }
    ShortBlack extends Coffee单品构造中初始化描述及价格
    //装饰者中间层
    public class Decorator extends Drink {
    
        //可以是单品也可以是被包装过的单品
        private Drink drink;
    
        public Decorator(Drink drink) {
            this.drink = drink;
        }
    
        public float cost() {
            //返回装饰者(调料)的价格+单品或者被包装过的单品的价格(被包装过的单品就是继承自装饰者的调料)
            return super.getPrice() + drink.cost();
        }
    
        @Override
        public String getDescription() {
            return super.getDescription() + "&&" + drink.getDescription();
        }
    }
    装饰者中间层Decorator extends Drink,装饰者依附于主体或混合主体,所以要有主体或混合主体对象,其cost总消费为装饰者价格加上主体或混合主体消费,描述为装饰者描述和主体描述
    public class Chocolate extends Decorator {
        public Chocolate(Drink drink) {
            super(drink);
            super.setDescription("Chocolate");
            super.setPrice(3.0f);
        }
    }
    Chocolate extends Decorator装饰者依附于主体或混合主体,所以构造中传入主体,设置装饰者描述及价格
    public class Milk extends Decorator {
        public Milk(Drink drink) {
            super(drink);
            super.setDescription("Milk");
            super.setPrice(2.0f);
        }
    }
    Milk extends Decorator装饰者依附于主体或混合主体,所以构造中传入主体,设置装饰者描述及价格
    public class Soy extends Decorator {
        public Soy(Drink drink) {
            super(drink);
            super.setDescription("Soy");
            super.setPrice(1.0f);
        }
    }
    Soy extends Decorator装饰者依附于主体或混合主体,所以构造中传入主体,设置装饰者描述及价格

    测试代码:

    public class CoffeeBar {
    
        public static void main(String[] args) {
            Drink order;
            order = new Decaf();
            System.out.println("order price:" + order.cost());
            System.out.println("order desc:" + order.getDescription());
    
            System.out.println("***********************************");
    
            order = new LongBlack();
            order = new Milk(order);
            order = new Chocolate(order);
            order = new Chocolate(order);
            System.out.println("order2 price:" + order.cost());
            System.out.println("order2 desc:" + order.getDescription());
        }
    
    }
    应用测试代码CoffeeBar
  • 相关阅读:
    Create, Read, Write, Copy, Move and Delete a Text File using C#
    财富人生访谈
    aspnetdb数据库简介
    asp.net基于Profile和Provider技术实现购物车
    IIS7的FTP设置
    DataRow[]用作DataSource找不到列的问题
    SMTP 550错误
    简单的文件上传代码
    选取哪个字段作为分区依据
    IIS7的虚拟目录设置独立应用程序池
  • 原文地址:https://www.cnblogs.com/hujiapeng/p/8059347.html
Copyright © 2020-2023  润新知