• 设计模式-Decorator模式(装饰者模式)


    装饰者模式

    假如现在有一块蛋糕, 加上奶油就是奶油蛋糕。如果继续再加上草莓,就是草莓蛋糕,再加点蜡烛,就变成了生日蛋糕。不论是蛋糕、奶油蛋糕、草莓蛋糕还是生日蛋糕,它们的核心都是蛋糕。

    像这样不断地为对象添加装饰的设计模式被称为Decorator模式。

    这个添加的过程有点类似于套娃。就是一个很原始的对象,一直在它外层套东西,不断地装饰它。

    代码实现

    示例程序的功能是给文字添加装饰边框,这里所谓的装饰边框是指用"-“,”+“,”|"等字符组成的边框。

    Component角色,抽象的”被装饰对象“,增加功能时的核心角色,比如定义了三个抽象方法,分别是获取字符串数组的列数,行数,以及输出第几行。还有一个默认方法是输出全部行

    public abstract class Display {
        public abstract int getColumns();
        public abstract int getRows();
        public abstract String getRowText(int row);
    
        public final void show() {
            for (int i = 0; i < getRows(); i++) {
                System.out.println(getRowText(i));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ConcreteComponent角色,具体的被装饰对象

    public class StringDisplay extends Display {
    
        private String string;
    
        public StringDisplay(String string) {
            this.string = string;
        }
    
        @Override
        public int getColumns() {
            return string.getBytes().length;
        }
    
        @Override
        public int getRows() {
            return 1;
        }
    
        @Override
        public String getRowText(int row) {
            if (row == 0) {
                return string;
            } else {
                return null;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Decorator(装饰物)角色,该角色具有与Component角色相同的接口(API),在它内部保存了被装饰对象——Component角色

    public abstract class Border extends Display {
        protected Display display;      // 表示被装饰物
    
        public Border(Display display) {
            this.display = display;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ConcreteDecorator(具体的装饰物)

    public class SideBorder extends Border {
    
        private char borderChar;
    
        public SideBorder(Display display, char borderChar) {
            super(display);
            this.borderChar = borderChar;
        }
    
        @Override
        public int getColumns() {
            return 1 + display.getColumns() + 1;
        }
    
        @Override
        public int getRows() {
            return display.getRows();
        }
    
        @Override
        public String getRowText(int row) {
            return borderChar + display.getRowText(row) + borderChar;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    public class FullBorder extends Border {
        public FullBorder(Display display) {
            super(display);
        }
    
        @Override
        public int getColumns() {
            return 1 + display.getColumns() + 1;
        }
    
        @Override
        public int getRows() {
            return 1 + display.getRows() + 1;
        }
    
        @Override
        public String getRowText(int row) {
            if (row == 0) {
                return "+" + makeLine('-', display.getColumns()) + "+";
            } else if (row == display.getRows() + 1) {
                return "+" + makeLine('-', display.getColumns()) + "+";
            } else {
                return "|" + display.getRowText(row-1) + "|";
            }
        }
    
        private String makeLine(char ch, int count) {
            StringBuffer buf = new StringBuffer();
            for (int i = 0; i < count; i++) {
                buf.append(ch);
            }
            return buf.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    测试类

    public class Test {
        public static void main(String[] args) {
            Display d1 = new StringDisplay("hello,world");
            Display d2 = new UpDownBorder(d1, '-');
    
            d2.show();
    
    
            Display d4 = new FullBorder(
                    new UpDownBorder(
                            new SideBorder(
                                    new UpDownBorder(
                                            new SideBorder(
                                                    new StringDisplay("helloWorld")
                                                    , '*'
                                            ),'='
                                    ), '/'
                            ), '|'
                    )
            );
            d4.show();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在Decorator模式中,装饰边框与被装饰物具有一致性,类似于Composite模式。不过,Decorator模式虽然与Composite模式一样,都具有递归结构,但是他们的使用目的不同,Decorator模式的主要目的是通过添加装饰物来增加对象的功能。

    为什么使用装饰者模式

    1. 接口(API)的透明性,因为装饰物也是被装饰物的子类,所以即便被装饰物被边框装饰起来了,接口(API)也不会被因此起来
    2. 在不改变被装饰物的前提下增加功能
    3. 可以动态的增加功能

    在这里插入图片描述

  • 相关阅读:
    SWAGGER 出错解决
    二叉树刷题
    【跟学C++】C++映射类——map/multimap类(Study17)
    vsCode之Live Server
    Android高版本读取沙盒目录apk解析安装失败解决方案
    SpringBoot原理篇
    Linux Day18 TCP_UDP协议及相关知识
    一篇文章入门循环神经网络RNN
    蓝桥杯 灭鼠先锋 博弈
    【Linux网络编程】 I/O复用
  • 原文地址:https://blog.csdn.net/weixin_44030848/article/details/126216187