工厂模式
工厂模式是一种设计模式,指在通过使用工厂函数或构造函数来创建对象;
它提供了一种灵活的方式来创建对象实例,而无需直接调用构造函数或使用new关键字;
可以分类,解耦;
可以扩展多个类(派生类、平行类等);
创建逻辑也可以自由扩展;
下面是一个使用工厂函数实现工厂模式的示例:
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')
}
}
工厂函数: create
为何没有返回 class 而是一个接口,因为依赖倒置原则,即任何一个 class 实现接口即可
class Creators {
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')
}
}
使用工厂函数创建实例:
const creator = new Creator()
const p1 = creator.create('p1')
const p2 = creator.create('p2')
const p3 = creator.create('p3')
UML 类图演示:
JQuery
工厂模式 JQuery 原理:
class JQuery {
selector: string // 选择器
length: number
constructor(selector: string) {
const domList = Array.from(document.querySelectorAll(selector)) // DOM元素
const length = domList.length // 元素集合长度
for (let i = 0; i < length; i++) {
this[i] = domList[i]
}
this.selector = selector
this.length = length
}
append(elem: HTMLElement): JQuery {
// append 的操作...
return this
}
addClass(className: string): JQuery {
// addClass 的操作...
return this
}
// ... methods ...
}
创建工厂函数,以及TS声明扩展 window 全局的属性
declare interface Window {
$: (selector: string) => JQuery
}
function $(selector: string) {
return new JQuery(selector)
}
window.$ = $
console.log($('p')) // test
在 vue 中的模板,react 的 jsx 中,render 函数生成 vNode 对象,使用的也是工厂模式
Vue template
在线编译 https://vue-next-template-explorer.netlify.app/
<div>
<span>文字</span>
<span :id="hello" class="message">{{ msg }}</span>
</div>
会编译出 _createXX 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: "message"
}, _toDisplayString(_ctx.msg), 9 , ["id"])
]))
}
React createElement
在线编译 https://www.babeljs.cn/repl
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(" "))
);
其大概原理:
class Vnode(tag, attrs, children) {
// ...
}
React.createElement = function (tag, attrs, children) {
return new Vnode(tag, attrs, children)
}