• Typescript 组合模式(Composite)


    请仔细阅读下面代码,理解其中的设计理念。

     
    composite.jpg

    组合模式

    组合模式: 将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

    实际场景

    为了方便我们对多个文件的管理,我们引入了“文件夹-文件”的模式。将具有统一性质的文件放入一个文件夹中,将具有统一性质的文件夹再放入另一个文件夹中。可以对整个文件夹系统进行文件的搜索,也可以对某一个文件夹进行搜索。让文件管理变得简单。
    而“文件夹-文件”这种结构就是典型 的组合模式。

    组合模式的结构

    • Component 是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
    • Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。
    • Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。

    组合模式的例子

    现在要实现一个文件夹文件树

    Node枚举

    /* node-type-enum.ts */
    enum NodeTypeEnum {
        ImageFile = 'image',
        TextFile = 'text',
        Folder = 'folder',
    }
    
    export {
        NodeTypeEnum
    }
    

    Node抽象类

    /* abstract-node.ts */
    import { NodeTypeEnum } from './node-type-enum';
    
    export abstract class AbstractNode {
        protected name: string;
        protected type: NodeTypeEnum;
        protected children: AbstractNode[];
    
        public abstract add(node: AbstractNode): AbstractNode;
        public abstract getFileDeep(name: string): AbstractNode;
    }
    

    文件和文件夹基础类

    /* basic-file-folder.ts */
    import { AbstractNode } from './abstract-node';
    import { NodeTypeEnum } from './node-type-enum';
    
    export abstract class BasicFile extends AbstractNode {
        public add (file: BasicFile): BasicFile {
            console.error('文件类型不支持添加');
            return this;
        }
    
        public getFileDeep (name: string): BasicFile {
            if (name === this.name) {
                return this;
            }
            return null;
        }
    }
    
    export abstract class BasicFolder extends AbstractNode {
        protected constructor () {
            super();
            this.type = NodeTypeEnum.Folder;
            this.children = [];
        }
    
        public add (file: AbstractNode): BasicFolder {
            this.children.push(file);
            return this;
        }
    
        public getFileDeep (name: string): AbstractNode {
            if (this.name === name) {
                return this;
            }
            for (let index = 0; index < this.children.length; index++) {
                const node = this.children[index].getFileDeep(name);
                if (node) {
                    return node;
                }
            }
            return null;
        }
    }
    

    文件类

    /* files.ts */
    import { BasicFile } from './basic-file-folder';
    import { NodeTypeEnum } from './node-type-enum';
    
    export class ImageFile extends BasicFile {
        constructor (name: string) {
            super();
            this.name = name;
            this.type = NodeTypeEnum.ImageFile;
        }
    }
    
    export class TextFile extends BasicFile {
        constructor (name: string) {
            super();
            this.name = name;
            this.type = NodeTypeEnum.TextFile;
        }
    }
    

    文件夹类

    /* folder.ts */
    import { BasicFolder } from './basic-file-folder';
    
    export default class SystemFolder extends BasicFolder{
        constructor(name){
            super();
            this.name = name;
        }
    }
    

    客户端

    /* client.ts */
    import { ImageFile, TextFile } from './files';
    import SystemFolder from './folder';
    
    export default class Client {
        public static initTree (): SystemFolder {
            const folder1: SystemFolder = new SystemFolder('根文件夹');
            const folder2: SystemFolder = new SystemFolder('图像文件夹');
            const folder3: SystemFolder = new SystemFolder('文本文件夹');
    
            const image1: ImageFile = new ImageFile('a.jpg');
            const image2: ImageFile = new ImageFile('b.jpg');
    
            const text1: TextFile = new TextFile('a.txt');
            const text2: TextFile = new TextFile('b.txt');
    
            folder2.add(image1).add(image2);
            folder3.add(text1).add(text2);
            folder1.add(folder2).add(folder3);
    
            return folder1;
        }
    }
    const tree = Client.initTree();
    const aJpg = tree.getFileDeep('a.jpg');
    console.log(aJpg);
    
    

    组合模式的利弊

    利:

    • 减少大量手工遍历数组或其他数据的粘合性代码
    • 组合模式中各个对象耦合非常松散,更容易改变他们或互换位置,有利于代码重构
    • 让代码有一个出色的层次体系,客户端调用更方便

    弊:
    组合模式掩盖了他所支持的每一种操作的代价。如果层次体系很大的话,系统的性能将会收到影响。



    作者:我不叫奇奇
    链接:https://www.jianshu.com/p/1f8c6ebaf6b6
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    数据库分页
    SpringBoot 集成 MQTT
    mybatis的级联查询-懒加载遇到的序列化问题
    springboot学习:第二天
    SpringSecurity学习
    大日志文件查看方式
    logger(七)、springBoot的日志源码查看(LogBack + slf4j)——配置的实际工作类Action
    logger(六)、springBoot的日志源码查看(LogBack + slf4j)—— ContextInitializer
    logger(五)、springBoot的日志源码查看(LogBack + slf4j)——Appender
    logger(四)、springBoot的日志源码查看(LogBack + slf4j)——记录日志
  • 原文地址:https://www.cnblogs.com/wodehao0808/p/14103773.html
Copyright © 2020-2023  润新知