美文网首页
Decorator模式(装饰器模式)

Decorator模式(装饰器模式)

作者: 涅槃快乐是金 | 来源:发表于2020-12-14 10:17 被阅读0次

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

    介绍

    • 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
    • 主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
    • 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
    • 缺点:
      1.多层装饰比较复杂。
      2.会导致程序中增加很多功能类似的很小的类
    • 使用场景:
      1、扩展一个类的功能。
      2、动态增加功能,动态撤销。

    注意事项:可代替继承。

    示例

    Display.ts 用于显示字符串的抽象类
    export default abstract class Display {
        public abstract getColumns(): number;//获取横向字符数
        public abstract getRows(): number;//获取纵向行数
        public abstract getRowText(row: number): string;//获取第row行的字符串
        /**
          *显示所有字符
        */
        public show(): void {
            for (let i = 0; i < this.getRows(); i++) {
                console.log(this.getRowText(i));
            }
        }
    }
    
    StringDisplay.ts 用于显示单行字符串的类
    import Display from "./Display";
    
    export default class StringDisplay extends Display {
        private str: string;//要显示的字符串
        constructor(str: string) {
            super();
            this.str = str;
        }
    
        public getColumns(): number {//字符数
            return this.str.length;
        }
        public getRows(): number {//行数1
            return 1;
        }
        public getRowText(row: number): string {//只显示第一行
            if (row == 0) {
                return this.str;
            } else {
                return null;
            }
        }
    }
    
    Border.ts 用于显示装饰边框的抽象类
    import Display from "./Display";
    
    export default abstract class Border extends Display {
        protected display: Display;//装饰物
        constructor(display: Display) {
            super();
            this.display = display;
        }
    }
    
    SideBorder.ts 用于显示左右边框的类
    import Display from "./Display";
    import Border from "./Border";
    
    export default class SideBorder extends Border {
        private borderChar: string;//装饰边框的字符
        constructor(display: Display, ch: string) {//指定Display和装饰边框字符
            super(display);
            this.borderChar = ch;
        }
        public getColumns(): number {
            return 1 + this.display.getColumns() + 1;//字符数加上两侧边框的字符数
        }
        public getRows(): number {
            return this.display.getRows();
        }
        public getRowText(row: number) {//字符串加上边框
            return this.borderChar + this.display.getRowText(row) + this.borderChar;
        }
    }
    
    FullBorder.ts 显示上下左右边框
    import Display from "./Display";
    import Border from "./Border";
    
    export default class FullBorder extends Border {
        constructor(display: Display) {
            super(display);
        }
        public getColumns(): number {
            return 1 + this.display.getColumns() + 1;//增加左右边框字符数
        }
        public getRows(): number {
            return this.display.getRows() + 2;//增加上下边框字符数
        }
        public getRowText(row: number) {
            if (row == 0 || row == this.display.getRows() + 1) {//上线边框
                return `+${this.makeLine('-', this.display.getColumns())}+`;
            } else {
                return `|${this.display.getRowText(row - 1)}|`;//左右边框
            }
        }
        private makeLine(ch: string, count: number) {
            let str = "";
            for (let i = 0; i < count; i++) {
                str = str + ch;
            }
            return str;
        }
    }
    
    index.ts
    import Display from "./Display";
    import StringDisplay from "./StringDisplay";
    import SideBorder from "./SideBorder";
    import FullBorder from "./FullBorder";
    
    const b1: Display = new StringDisplay("Hello,World.");//直接显示
    const b2: Display = new SideBorder(b1, '#');//增加左右边框'#'
    const b3: Display = new FullBorder(b2);//上下左右都加边框
    
    b1.show();
    b2.show();
    b3.show();
    
    const b4: Display = new SideBorder(//多层边框
        new FullBorder(
            new FullBorder(
                new SideBorder(
                    new FullBorder(new StringDisplay("Hello,World.")), "*"
                )
            )
        ), "/"
    )
    
    b4.show();
    
    result
    Hello,World.                       //b1
    #Hello,World.#                     //b2   
    +--------------+                  //b3
    |#Hello,World.#|
    +--------------+
    /+------------------+/            //b4
    /|+----------------+|/
    /||*+------------+*||/
    /||*|Hello,World.|*||/
    /||*+------------+*||/
    /|+----------------+|/
    /+------------------+/
    

    类图

    类图

    角色

    • Component
      增加功能时的核心角色。示例中Display类扮演该角色
    • ConcreteComponent
      该角色实现了Component角色定义的接口。在示例中StringDisplay类扮演该角色
    • Decorator(装饰物)
      该角色具有与Component角色相同的接口,在内部保存了了被装饰的对象->Component。Decorator橘色知道自己要装饰的对象。在示例中,Border类扮演该角色
    • ConcreteDecorator(具体的装饰物)
      该角色是具体的Decorator角色,示例中SideBorder类和FullBorder类扮演该角色

    相关文章

      网友评论

          本文标题:Decorator模式(装饰器模式)

          本文链接:https://www.haomeiwen.com/subject/qlykgktx.html