likes
comments
collection
share

前端设计模式之工厂模式(三)

作者站长头像
站长
· 阅读数 17
  • 创建对象的一种方式。不用每次都亲自创建对象,而是通过一个既定的“工厂”来生产对象
  • 比如我们需要买一个汉堡,其实是让服务员(工厂方法)做出来(new A())给客户,而不是自己做
  • 遇到 new class 时,考虑工厂模式

伪代码理解

OOP 中,默认创建对象一般是 new class ,但一些情况下用 new class 会很不方便

// 伪代码
let f1;
class Foo {}

if (a) {
  f1 = Foo(x);
}
if (b) {
  f2 = Foo(x, y);
}

此时就需要一个“工厂”,把创建者和 class 分离,符合开放封闭原则

function create(a, b) {
  if (a) {
    return Foo(x);
  }
  if (b) {
    return Foo(x, y);
  }
}

const f1 = create(a, b);

简易工厂模式

前端设计模式之工厂模式(三)

class Product {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  fn1() {
    alert("product fn1");
  }
  fn2() {
    alert("product fn2");
  }
}

class Creator {
  create(name: string): Product {
    return new Product(name);
  }
}

const creator = new Creator();
creator.create("p1");
creator.create("p2");
creator.create("p3");

标准的工厂模式

前端设计模式之工厂模式(三)

interface IProduct {
  name: string;
  fn1: () => void;
  fn2: () => void;
}

class Product1 implements IProduct {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  fn1() {
    alert("product1 fn1");
  }
  fn2() {
    alert("product1 fn2");
  }
}

class Product2 implements IProduct {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  fn1() {
    alert("product2 fn1");
  }
  fn2() {
    alert("product2 fn2");
  }
}

class Creator {
  create(type: string, name: string): IProduct {
    if (type === "p1") {
      return new Product1(name);
    }
    if (type === "p2") {
      return new Product2(name);
    }
    throw new Error("Invalid type");
  }
}
function User(name, age, career, work) {
  this.name = name;
  this.age = age;
  this.career = career;
  this.work = work;
}

function Factory(name, age, career) {
  let work;
  switch (career) {
    case "coder":
      work = ["写代码", "写系分", "修Bug"];
      break;
    case "product manager":
      work = ["订会议室", "写PRD", "催更"];
      break;
    case "boss":
      work = ["喝茶", "看报", "见客户"];
    case "xxx":
    // 其它工种的职责分配
  }
  return new User(name, age, career, work);
}

Factory("yunmu", 18, "coder");

是否符合设计模式

  • 工厂和类分离,解耦
  • 可以扩展多个类
  • 工厂的创建逻辑也可以自由扩展

符合开放封闭原则

工厂模式场景

jQuery $('div')

// 扩展 window.$
declare interface Window {
  $: (selector: string) => JQuery;
}

class JQuery {
  selector: string;
  length: number;

  constructor(selector: string) {
    const domList = Array.prototype.slice.call(document.querySelectorAll(selector));
    const length = domList.length;
    for (let i = 0; i < length; i++) {
      this[i] = domList[0];
    }

    this.selector = selector;
    this.length = length;
  }

  append(elem: HTMLElement): JQuery {
    // ...
    return this;
  }

  addClass(key: string, value: string): JQuery {
    // ...
    return this;
  }

  html(htmlStr: string): JQuery | string {
    if (htmlStr) {
      // set html
      return this;
    } else {
      // get html
      const html = "xxx";
      return html;
    }
  }
}

function $(selector: string) {
  return new JQuery(selector);
}
window.$ = $;

const $div = $("div");
// // 伪代码,演示 jquery 实例的结构
// const jquery = {
//     selector: 'div',
//     length: 3,
//     '0': div1,
//     '1': div2,
//     '2': div3
// }

Vue _createElementVNode

在线编译:vue-next-template-explorer.netlify.app/

<div>
  <span>静态文字</span>
  <span :id="hello" class="bar">{{ msg }}</span>
</div>

会编译出很多 _createXxx JS 代码。这些就是工厂函数,创建 vnode

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", null, [
    _createElementVNode("span", null, "静态文字"),
    _createElementVNode("span", {
      id: _ctx.hello,
      class: "bar"
    }, _toDisplayString(_ctx.msg), 9 /* TEXT, PROPS */, ["id"])
  ]))
}

React createElement

在线编译:www.babeljs.cn/repl

在 React 中使用 JSX 语法

const profile = <div>
  <img src="avatar.png" className="profile" />
  <h3>{[user.firstName, user.lastName].join(' ')}</h3>
</div>

这是一种语法糖,编译之后就会是:

// 返回 vnode
const profile = React.createElement("div", null,
    React.createElement("img", { src: "avatar.png", className: "profile" }),
    React.createElement("h3", null, [user.firstName, user.lastName].join(" "))
);

其实 React.createElement 也是一个工厂,模拟代码

class Vnode(tag, attrs, children) {
    // ...省略内部代码...
}
React.createElement =  function (tag, attrs, children) {
    return new Vnode(tag, attrs, children);
}
转载自:https://juejin.cn/post/7197034140487188540
评论
请登录