《javascript设计模式》学习笔记七:Javascript面向对象程序设计组合模式详解

下面是《Javascript设计模式》学习笔记七:Javascript面向对象程序设计组合模式详解的完整攻略。

什么是组合模式

组合模式是一种结构型设计模式,它通过将对象组合成树形结构来表示部分-整体的层次关系,使得用户对单个对象和组合对象的使用具有一致性。

换句话说,组合模式就是将对象组织成树形结构,以表示“部分-整体”的层次结构,并允许用户对单个对象和组合对象进行相同的操作,从而实现对整个树形结构的操作。

组合模式的结构

组合模式涉及到以下几种角色:

  1. 抽象类:组合中的对象声明接口,实现一些公共接口,同时也能定义一些默认行为或属性。
  2. 叶节点类:实现抽象节点所声明的接口,为组合中的叶节点对象提供公共接口。
  3. 组合节点类:组合对象,通常会存储它的子节点,实现抽象节点所声明的接口。

组合模式的实现

下面我们通过两个示例来演示组合模式的实现。

示例1:餐厅菜单的实现

我们要实现一个菜单系统,分别包含面条、米饭和饮料三种类型的商品,这些商品都具有相同的基本属性,如价格、名称等。同时,我们还要实现对整个菜单的操作,如计算总价格等。

首先我们需要定义一个抽象类MenuItem,来定义各个商品的公共接口:

class MenuItem {
  constructor(name, price) {
    this.name = name;
    this.price = price;
  }
  getPrice() {
    return this.price;
  }
  getName() {
    return this.name;
  }
  getDescription() {
    throw new Error("该方法必须由子类重写");
  }
  print() {
    console.log(`${this.getName()} - ${this.getPrice()}`);
  }
}

然后,我们定义面条、米饭和饮料三个叶节点类,分别继承MenuItem类并实现各自的公共接口:

class Noodles extends MenuItem {
  constructor(name, price) {
    super(name, price);
  }
  getDescription() {
    return "面条";
  }
}

class Rice extends MenuItem {
  constructor(name, price) {
    super(name, price);
  }
  getDescription() {
    return "米饭";
  }
}

class Drink extends MenuItem {
  constructor(name, price) {
    super(name, price);
  }
  getDescription() {
    return "饮料";
  }
}

最后,我们定义菜单组合类Menu,来组合各个商品节点,并实现菜单的公共接口:

class Menu extends MenuItem {
  constructor() {
    super("菜单", 0);
    this.menuItems = [];
  }
  add(item) {
    this.menuItems.push(item);
  }
  remove(item) {
    const index = this.menuItems.indexOf(item);
    this.menuItems.splice(index, 1);
  }
  getPrice() {
    return this.menuItems.reduce((prev, item) => {
      return prev + item.getPrice();
    }, 0);
  }
  getDescription() {
    return "菜单";
  }
  print() {
    console.log(`------ ${this.getName()} -------`);

    this.menuItems.forEach((item) => {
      item.print();
    });
  }
}

这样,我们就可以创建各种商品节点,并使用菜单组合类将它们组合成为一个树形结构:

const noodles1 = new Noodles("羊肉面", 15);
const noodles2 = new Noodles("牛肉面", 12);
const rice1 = new Rice("鸡蛋炒饭", 11);
const drink1 = new Drink("可乐", 5);
const drink2 = new Drink("奶茶", 8);

const menu = new Menu();
menu.add(noodles1);
menu.add(noodles2);
menu.add(rice1);

const drinkMenu = new Menu();
drinkMenu.add(drink1);
drinkMenu.add(drink2);

menu.add(drinkMenu);

menu.print();  // 输出所有商品的名称和价格
console.log("总价格:", menu.getPrice());  // 输出所有商品的总价格

输出结果如下:

------ 菜单 -------
羊肉面 - 15
牛肉面 - 12
鸡蛋炒饭 - 11
------ 菜单 -------
可乐 - 5
奶茶 - 8
总价格: 51

示例2:文件系统的实现

我们要实现一个文件系统,其中包括了文件和文件夹两种节点,文件节点和文件夹节点具有相同的基本属性,如名称、类型等。同时,我们还要实现对整个文件系统的操作,如计算文件总数等。

同样地,我们需要定义一个抽象类Node,来定义各个节点的公共接口:

class Node {
  constructor(name, type) {
    this.name = name;
    this.type = type;
  }
  getName() {
    return this.name;
  }
  getType() {
    return this.type;
  }
  getSize() {
    throw new Error("该方法必须由子类重写");
  }
  addChild() {
    throw new Error("该方法必须由子类重写");
  }
  removeChild() {
    throw new Error("该方法必须由子类重写");
  }
  getChild() {
    throw new Error("该方法必须由子类重写");
  }
  getChildren() {
    throw new Error("该方法必须由子类重写");
  }
}

然后,我们定义文件节点和文件夹节点两个叶节点类,分别继承Node类并实现各自的公共接口:

class File extends Node {
  constructor(name, size) {
    super(name, "文件");
    this.size = size;
  }
  getSize() {
    return this.size;
  }
}

class Folder extends Node {
  constructor(name) {
    super(name, "文件夹");
    this.children = [];
  }
  addChild(node) {
    this.children.push(node);
  }
  removeChild(node) {
    const index = this.children.indexOf(node);
    if (index !== -1) {
      this.children.splice(index, 1);
    }
  }
  getChild(index) {
    return this.children[index];
  }
  getChildren() {
    return this.children;
  }
  getSize() {
    return this.children.reduce((prev, child) => {
      return prev + child.getSize();
    }, 0);
  }
}

最后,我们定义文件系统组合类FileSystem,将文件和文件夹节点都组合起来,并实现对整个文件系统的操作的公共接口:

class FileSystem extends Folder {
  constructor(name) {
    super(name);
  }
  getFileCount() {
    return this.getChildren().filter((child) => {
      return child.getType() === "文件";
    }).length;
  }
  getFolderCount() {
    return this.getChildren().filter((child) => {
      return child.getType() === "文件夹";
    }).length;
  }
  getSize() {
    return this.children.reduce((prev, child) => {
      return prev + child.getSize();
    }, 0);
  }
}

这样,我们就可以创建各种文件和文件夹节点,并使用文件系统组合类将它们组合成为一个树形结构:

const folder1 = new Folder("目录1");
const folder2 = new Folder("目录2");
const folder3 = new Folder("目录3");

const file1 = new File("文件1", 50);
const file2 = new File("文件2", 20);
const file3 = new File("文件3", 10);

folder1.addChild(file1);
folder1.addChild(folder2);

folder2.addChild(file2);
folder2.addChild(folder3);

folder3.addChild(file3);

const fs = new FileSystem("根目录");
fs.addChild(folder1);

console.log("文件总数:", fs.getFileCount());
console.log("文件夹总数:", fs.getFolderCount());
console.log("文件系统总大小:", fs.getSize());

输出结果如下:

文件总数: 3
文件夹总数: 3
文件系统总大小: 80

总结

组合模式是一种结构型设计模式,可以方便地组织对象成树形结构,实现“部分-整体”的操作。通过两个示例,我们演示了组合模式的实现方法,并学习了其中的一些经验与技巧。这些技巧包括:抽象类的使用、叶节点类的实现、组合节点类的实现等。掌握了这些技巧,我们就可以快速地实现复杂的树形结构操作。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:《javascript设计模式》学习笔记七:Javascript面向对象程序设计组合模式详解 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • C# 语言入门基础介绍

    C# 语言入门基础介绍 C# 是一种通用、面向对象的编程语言,由微软公司开发,广泛应用于业界。在学习 C# 之前,需要了解一些基本的编程概念。 1. C# 语言的特点 C# 语言具有以下特点: 易于学习:语法简单,与其他语言相比较易于理解。 安全性高:内置类型检查和内存管理机制确保程序的稳定和安全。 面向对象:支持面向对象编程,便于开发大型应用程序。 多平台…

    Java 2023年5月19日
    00
  • Java SpringBoot核心源码详解

    Java SpringBoot核心源码详解 简介 本篇攻略主要讲解Java SpringBoot核心源码的相关内容,详细解析SpringBoot框架的设计和实现原理。同时,为了让读者更加深入理解,我们将通过两条示例代码来解释相关概念。 SpringBoot框架基础 SpringBoot框架基于Spring框架之上,通过提供许多默认配置和简化部署流程等功能,让…

    Java 2023年5月15日
    00
  • java的继承原理与实现方法详解

    让我们先从继承的概念入手。继承(Inheritance)是一种面向对象的编程技术,它允许某个类(子类)去继承它的另一个类(父类)的属性和方法。这个技术可以减少重复性代码,提高代码复用性和可维护性。在 Java 中,子类通过关键字 extends 来继承父类。 继承原理 Java 使用类的继承机制来实现继承。在 Java 中,一个类可以通过关键字 extend…

    Java 2023年5月18日
    00
  • 中英文对照Stargate中的科学与技术

    “中英文对照Stargate中的科学与技术”攻略 为什么需要这个攻略? 《星际之门》(Stargate)是一部著名的科幻电视剧,其中出现了许多科学与技术术语和概念。对于英语不是母语的观众,有时会很难理解这些术语的含义。因此,本攻略旨在为大家提供一份中英文对照的Stargate科学与技术词汇表,方便观众更好地理解这部电视剧。 收集信息 收集中英文对照的Star…

    Java 2023年5月19日
    00
  • Java利用for循环打印菱形的实例教程

    下面是Java利用for循环打印菱形的实例教程的完整攻略。 题目分析 我们需要打印一个菱形,实际上就是一个对称的四边形。那么我们可以通过for循环嵌套来实现。 代码实现 import java.util.Scanner; public class PrintDiamond { public static void main(String[] args) { …

    Java 2023年5月26日
    00
  • 使用AngularJS来实现HTML页面嵌套的方法

    使用AngularJS来实现HTML页面嵌套是AngularJS的基本用法之一。下面是实现过程的完整攻略。 环境配置 首先需要准备好配置AngularJS的环境。可以通过以下步骤在本地搭建环境: 下载并安装nodejs环境; 利用npm命令安装angularjs,命令为:npm install angular; 嵌套HTML页面 1. 创建HTML页面 首先…

    Java 2023年6月15日
    00
  • 类似Object监视器方法的Condition接口(详解)

    下面我会详细讲解“类似Object监视器方法的Condition接口(详解)”的完整攻略。 Background 在Java中,有时我们需要等待一些特定条件的发生,才能继续执行接下来的操作。此时,我们可以使用Object的监视器方法,或者使用JDK1.5出现的Lock机制,但是它们都存在一些问题,比如在多线程环境下容易出现死锁等问题。为解决这些问题,Java…

    Java 2023年5月26日
    00
  • Spring Data JPA查询方式及方法名查询规则介绍

    Spring Data JPA查询方式及方法名查询规则介绍 Spring Data JPA是Spring Data中用于简化基于JPA开发的数据访问层的框架。它为我们提供了很多简洁、方便的查询方式,本文将介绍Spring Data JPA的查询方式及方法名查询规则。 简单查询 1. 根据ID查询实体 Optional<User> findById…

    Java 2023年6月3日
    00
合作推广
合作推广
分享本页
返回顶部