• 设计模式--装饰者模式


    设计模式--装饰者模式

    今天偶然的机会接触到了装饰者模式,当我们需要很多的子类组合去实现一个功能时,可以考虑下使用装饰者模式。例如衣服有尺寸、规格、颜色,咖啡有种类、糖度、温度,这样的动态组合会衍生出指数增长的子类,装饰者模式就适用于这样的情景。

    1、适用场景

    • 使用子类拓展一个类的功能呈现爆炸性增长,请改为装饰者模式
    • 动态撤销、增加一个类的功能,各个功能类相互独立。

    2、角色

    • 抽象构件角色(Component):定义一个接口或抽象类,装饰者角色通过它实现给具体的构件角色赋能,例如衣服。
    • 具体构件角色(ConcreteComponent):实现或继承抽象构件角色,被装饰者角色赋能的对象,例如裤子、外套。
    • 抽象装饰者角色(Decorator): 同样实现或继承抽象构件角色,一般情况下是一个抽象类,用来拓展抽象构件角色的功能,例如拓展衣服的尺寸。
    • 具体装饰者角色(ConcretDecorator) :继承于抽象装饰者角色,实现具体的赋能动作,例如尺寸为 XL 。

    组件构成参考博客:装饰者角色组成

    看了上面的描述你可能还会有点懵,请看下面的构图:

    5

    看完之后是否有一定的印象了呢? ConcreteComponent 及 ConcreteDecorator 都可以拓展,且相互独立,这便是装饰者模式。

    3、例子

    以衣服的材质、价格为例子演示下装饰者模式。

    衣服--抽象构件角色(Component)

    package com.lin.decorator;
    
    import java.math.BigDecimal;
    
    /**
     * 抽象构件角色(Component),衣服总称
     */
    public abstract class Clothes {
        String description = "clothes";
    
        /**
         * 衣服的描述
         *
         * @return 描述,具体构件角色可自定义描述
         */
        public String getDescription() {
            return description;
        }
        /**
         * 衣服的价格,由具体构件角色实现
         *
         * @return 价格
         */
        public abstract BigDecimal getCost();
    }
    

    裤子--具体构件角色

    package com.lin.decorator;
    
    import java.math.BigDecimal;
    /**
     * 具体构件角色(ConcreteComponent),裤子
     */
    public class Pants extends Clothes{
        /**
         * 裤子的描述
         */
        public Pants() {
            description = "Pants";
        }
    
        /**
         * 裤子的价格,此时是装饰前的。
         *
         * @return
         */
        @Override
        public BigDecimal getCost() {
            return new BigDecimal(40.0);
        }
    }
    

    背心--具体构件角色

    package com.lin.decorator;
    
    import java.math.BigDecimal;
    /**
     * 具体构件角色(ConcreteComponent),背心
     */
    public class Vest extends Clothes{
        /**
         * 背心的描述
         */
        public Vest() {
            description = "Vest";
        }
    
        /**
         * 背心的价格,此时是装饰前的。
         *
         * @return 价格
         */
        @Override
        public BigDecimal getCost() {
            return new BigDecimal(40.0);
        }
    }
    

    衣服材质--抽象装饰者角色

    package com.lin.decorator;
    
    import java.math.BigDecimal;
    
    /**
     * 抽象装饰者角色(Decorator), 衣服的材质
     */
    public abstract class MaterialDecorator extends Clothes {
        /**
         * 由具体装饰者角色(ConcreteDecorator)实现每一次的描述
         *
         * @return
         */
        public abstract String getDescription();
        /**
         * 由具体装饰者角色(ConcreteDecorator)实现每一次的价格计算
         *
         * @return
         */
        public abstract BigDecimal getCost();
    }
    

    雪纺--具体装饰者角色

    package com.lin.decorator;
    
    import java.math.BigDecimal;
    
    /**
     * 具体装饰者角色(ConcreteDecorator),衣服的材质为雪纺
     */
    public class Chiffon extends MaterialDecorator {
        private Clothes clothes;
        /**
         * 保存每一次雪纺装饰的构件角色
         *
         * @param clothes
         */
        public Chiffon(Clothes clothes) {
            this.clothes = clothes;
        }
    
        /**
         * 保留每一次雪纺装饰的描述
         *
         * @return 描述
         */
        @Override
        public String getDescription() {
            return clothes.getDescription() + " 雪纺";
        }
    
        /**
         * 保留每一次雪纺装饰的价格
         *
         * @return 价格
         */
        @Override
        public BigDecimal getCost() {
            return new BigDecimal(30.0).add(clothes.getCost());
        }
    }
    

    纤维--具体装饰者角色

    package com.lin.decorator;
    
    import java.math.BigDecimal;
    /**
     * 具体装饰者角色(ConcreteDecorator),衣服的材质为纤维
     */
    public class Fibre extends MaterialDecorator {
        private Clothes clothes;
        /**
         * 保存每一次纤维装饰的构件角色
         *
         * @param clothes
         */
        public Fibre(Clothes clothes) {
            this.clothes = clothes;
        }
    
        /**
         * 保留每一次纤维装饰的描述
         *
         * @return 描述
         */
        @Override
        public String getDescription() {
            return clothes.getDescription() + " 纤维";
        }
    
        /**
         * 保留每一次纤维装饰的价格
         *
         * @return 价格
         */
        @Override
        public BigDecimal getCost() {
            return new BigDecimal(50.0).add(clothes.getCost());
        }
    }
    

    测试类

    package com.lin.controller;
    
    import com.lin.decorator.*;
    
    public class test {
    
        public static void main(String[] args) {
            Clothes clothes1 = new Pants();
            System.out.println(clothes1.getDescription() + " 价格为:" + clothes1.getCost());
    
            Clothes clothes2 = new Pants();
            clothes2 = new Fibre(clothes2);
            System.out.println(clothes2.getDescription() + " 价格为:" + clothes2.getCost());
    
            Clothes clothes3 = new Vest();
            clothes3 = new Chiffon(clothes3);
            System.out.println(clothes3.getDescription() + " 价格为:" + clothes3.getCost());
        }
    }
    

    运行结果如下:

    Pants 价格为:40
    Pants 纤维 价格为:90
    Vest 雪纺 价格为:70
    

    装饰者模式的写法多种多样,寻找自己易于理解的点实现类似的功能即可。

    4、缺点

    1、增加了抽象装饰者类和具体装饰者类,一定程度增加了系统的复杂度,加大了系统的学习和理解成本。

    2、灵活性也意味着更容易出错,对于多次被多次修饰的对象,调试时寻找错误可能需要找到多个地方。

    自我控制是最强者的本能-萧伯纳
  • 相关阅读:
    B题 hdu 1407 测试你是否和LTC水平一样高
    A题 hdu 1235 统计同成绩学生人数
    hdu 1869 六度分离(最短路floyd)
    hdu 2795 Billboard(线段树+单点更新)
    hdu 1754 I Hate It(线段树)
    hdu 1166敌兵布阵(线段树)
    hdu 1556(线段树之扫描线)
    Contest2073
    中南oj String and Arrays
    51nod 1459 迷宫游戏 (最短路径—Dijkstra算法)
  • 原文地址:https://www.cnblogs.com/CF1314/p/14349616.html
Copyright © 2020-2023  润新知