# 工厂模式创建对象以及实现继承

# 课程目标

  • 编写一个返回对象的工厂方法。
  • 描述私有函数和变量如何有用。
  • 使用工厂模式在对象中使用继承。
  • 掌握模块模式基础知识

# 使用工厂模式创建对象

工厂模式是一种众所周知的设计模式,广泛应用与软件工程领域,用于抽象创建特定对象的过程。

先看下在这种设计模式下,应该如何组织我们的代码,例如,我们可能会想要对象来描述一个人,并封装这个人可以做的所有事情

const Person = (name, age) => {
  return {
    name,
    age,
    birthday() {
      console.log(`${name}长大了一岁`);
      this.age++;
    },
    eat() {
      console.log(`${name}正在吃饭`);
    },
  };
};

//创建了两个人
const person1 = Person("Jack", 32);
const person2 = Person("Lisa", 5);

console.log(person1.name); //"Jack"
console.log(person2.age); //"5"
person2.birthday(); //"Lisa 长大了一岁"
console.log(person2.age); //"6"

阅读下面材料学习深入工厂模式

# 使用工厂模式实现继承

现在我们来看看如何在工厂模式下实现继承。比如我们希望再封装一个学生对象,学生对象应当继承于人

const Student = (name, age, job) => {
  const prototype = Person(name, age); //继承 Person 对象
  return Object.assign({}, prototype, {
    job,
    study() {
      console.log(`${name}正在学习`);
    },
  });
};

//创建一个学生
const student1 = Student("Jennie", 18, "student");
console.log(student1.name); //"Jennie"
console.log(student1.age); //"18"
student1.birthday(); //"Jennie 长大了一岁"
student1.study(); //"Jennie 正在学习"

由上可见对象 Student 继承了对象 Person 的属性:name,age 和方法: birthday,还具有自己的属性:job,以及方法:study

工厂模式很棒,因为它允许您选择要包含在新对象中的功能,比如,如果你只想继承对象 Person 的 eat 方法,不想继承 birthday 方法,您可以这样做:

const Student = (name, age, job) => {
  const { eat } = Person(name, age); //只继承了 eat 方法
  return Object.assign(
    {},
    { eat },
    {
      job,
      study() {
        console.log(`${name}正在学习`);
      },
    }
  );
};

const student2 = Student("Penny", 16, "student");
console.log(student2.name); //"Penny"
console.log(student2.age); //"18"
student2.eat(); //"Jennie 正在吃饭"
student2.birthday(); //报错 - Uncaught TypeError: student2.birthday is not a function

# 模块模式

模块模式实际上与工厂函数非常相似。主要区别在于它们的创建方式。

我们先来看一个模块:

const StringMethods = (() => {
  const uppercase = (str) => str.toUpperCase();
  const lowercase = (str) => str.toLowerCase();
  const capitalize = (str) =>
    str.slice(0, 1).toUpperCase() + str.slice(1).toLowerCase();

  return {
    uppercase,
    lowercase,
    capitalize,
  };
})();

console.log(StringMethods.uppercase("css")); // CSS
console.log(StringMethods.lowercase("JAVAScript")); // javascript
console.log(StringMethods.capitalize("html")); // Html

然而,模块模式不是创建一个我们可以反复使用来创建多个对象的工厂,而是将工厂包装在一个 IIFE(立即调用函数表达式)中,只暴露出我们需要调用的方法。

上一节我们学习了 IIFE,忘记的同学可以去回顾一下

阅读下面材料,学习模块模式基础知识

# 任务

现在你需要开发一个表单生成器,需要做到表单元素的自动生成。请你采用工厂模式来创建表单元素对象。

实现以 JavaScript 对象的方式定义表单及验证规则 表单配置参考示例如下:(不需要一致,仅为参考)

{
    label: '名称',                    // 表单标签
    type: 'input',                   // 表单类型
    validator: function () {...},    // 表单验证规
    rules: '必填,长度为4-16个字符',    // 填写规则提示
    success: '格式正确',              // 验证通过提示
    fail: '名称不能为空'               // 验证失败提示
}

  • 基于该配置项,实现一套逻辑,可以自动生成表单的展现、交互、验证
  • 使用你制作的表单工厂,在一个页面上创建两套样式不同的表单

注意事项

  • 实现中,尽可能考虑代码的可读性和可复用性
  • 尽量时表单配置、生成、样式、验证几个逻辑之间的耦合度足够低
  • 请注意代码风格的整齐、优雅
  • 代码中含有必要的注释
  • 不允许借助任何第三方组件库实现

# 相关参考