学习设计模式——组合模式

组合模式,又叫整体-部分模式,它允许你将对象组合成树形结构来表现
整体-部分层次结构,让使用者可以以一致的方式处理组合对象以及部分对象。

例如树形文件目录结构,就符合组合模式的特征
用组合模式实现,以下场景:

本地有一个【学习资料】文件夹,文件夹下有两个文件夹【大桥老师】和【小苍老师】,
两文件夹下分别各自有一些资料和文件夹,我们要在这些资料文件夹里找到大于2G的资料文件,
并输出文件名和大小。

/*
 * @Author: HotSuitor
 * @Date: 2020-03-18 17:14:19
 * @LastEditors: hs
 * @LastEditTime: 2020-03-18 18:33:35
 * @Description: hotsuitor@qq.com
 */

//  创建文件夹
var createFolder = function(name) {
  return {
    name: name,
    _children: [],
    // 在文件夹下创建文件夹或文件
    add: function(fileOfFolder) {
      this._children.push(fileOfFolder);
    },
    //扫描方法
    scan: function(cb) {
      this._children.forEach(function(child) {
        child.scan(cb);
      });
    }
  };
};
// 创建文件
var createFile = function(name, size) {
  return {
    name: name,
    size: size,
    //
    add: function() {
      throw new Error("文件下面不能创建文件");
    },
    scan: function(cb) {
      cb(this);
    }
  };
};

var foldMovies = createFolder("学习资料");

// 创建子文件夹,并放入根文件夹
var foldMovieDaQiao = createFolder("大桥老师");
foldMovies.add(foldMovieDaQiao);

var foldMovieXiaoCan = createFolder("小苍老师");
foldMovies.add(foldMovieXiaoCan);

// 添加学习资料
foldMovieDaQiao.add(createFile("如何骑马.avi", 1.2));
foldMovieDaQiao.add(createFile("优雅舞姿.avi", 1.7));
foldMovieDaQiao.add(createFile("射箭五十练.avi", 2.4));
foldMovieDaQiao.add(createFile("优雅喝酒.avi", 2.1));

foldMovieXiaoCan.add(createFile("海边如何防晒.mp6", 1.8));
foldMovieXiaoCan.add(createFile("如何布置房间.mp6", 1.5));
foldMovieXiaoCan.add(createFile("窗帘的设计.mp6", 2.7));

console.log("大于2G的学习资料有:");
foldMovies.scan(function(item) {
  if (item.size > 2) {
    console.log("name:" + item.name + " size:" + item.size);
  }
});

之前学过链模式,可以用链模式改造,简洁代码

// 链式改造
var createFolder = function(name) {
  return {
    name: name,
    _children: [],
    add: function(fileOfFolder) {
      this._children.push(fileOfFolder);
      return this;
    },
    scan: function(cb) {
      this._children.forEach(child => {
        child.scan(cb);
      });
    }
  };
};

var createFile = function(name, size) {
  return {
    name: name,
    size: size,
    add() {
      throw new Error("文件下不能创建文件");
    },
    scan(cb) {
      cb(this);
    }
  };
};

var foldMovies2 = createFolder("电影")
  .add(
    createFolder("漫威")
      .add(createFile("钢铁侠.mp4", 1.9))
      .add(createFile("蜘蛛侠.mp4", 2.1))
      .add(createFile("金刚狼.mp4", 2.3))
      .add(createFile("美国队长.mp4", 1.4))
  )
  .add(
    createFolder("DC电影")
      .add(createFile("蝙蝠侠.mp4", 2.4))
      .add(createFile("超人.mp4", 1.8))
  );
console.log("\n大于1.5G的学习资料有:");
foldMovies2.scan(function(item) {
  if (item.size > 1.5) {
    console.log("name:" + item.name + " size:" + item.size);
  }
});

实战,借助组合模式,实现dom树节点的创建

const createElement = function({ tag, attr, children }) {
  const node = tag
    ? document.createElement(tag)
    : document.createTextNode(attr.text);
  tag && Object.keys(attr).forEach(key => node.setAttribute(key, attr[key]));
  children &&
    children.forEach(child =>
      node.appendChild(createElement(child))
    );
  return node;
};

const ulElement = createElement({
  tag: 'ul',
  attr: {id: 'data-list'},
  children: [
    {
      tag: 'li',
      attr: {class: 'item'},
      children:[{attr:{text: 'item1'}}]
    },
    {
      tag: 'li',
      attr: {class: 'item'},
      children:[{attr:{text: 'item2'}}]
    },
    {
      tag: 'li',
      attr: {class: 'item'},
      children:[{attr:{text: 'item3'}}]
    },
  ]
})
console.log(ulElement);
document.body.appendChild(ulElement);
/* <ul id="data-list"><li class="item">item1</li><li class="item">item2</li><li class="item">item3</li></ul> */

vue和react的虚拟DOM也是这样类似的树形结构渲染DOM节点的

优缺点

优点:

  1. 由于组合对象和叶对象具有相同的接口,因此调用组合对象还是叶对象对使用者来说没有区别,使得使用者面向对象接口编程
  2. 对扩展友好,如何开闭原则,利于维护。如果想要在组合模式中增加一个节点比较容易,在目标组合节点中添加即可,不会影响到其他对象。
    缺点:
  3. 增加了系统的复杂性,如果树中的对象不多,不一定需要使用;
  4. 如果通过组合对象创建了太多对象,会增加系统负担。

适用场景

  1. 对象组织呈树形结构
  2. 使用者希望统一对待树形结构中的对象,比如用户不想写一堆if-else来处理树中的节点时
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值