前端设计模式之工厂模式(三)
- 创建对象的一种方式。不用每次都亲自创建对象,而是通过一个既定的“工厂”来生产对象
- 比如我们需要买一个汉堡,其实是让服务员(工厂方法)做出来(
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