创建型模式
构造器模式
对象的创建过程
function createPerson(name: string, age: number) {
const person = Object.create(null);
person.name = name;
person.age = age;
person.getName = function () {
return this.name;
};
person.getAge = function () {
return this.age;
};
return person;
}
const person1 = createPerson("李白", 18);
const person2 = createPerson("杜甫", 20);
不讲究属性和方法复用,比如person1
和person2
在内层中都是占用独立的空间
需注意,要使用Object.create(null)
创建一个独立的空白对象,让每次调用createPerson函数
都是生成的对象都是内存中独立的空间
单纯的构造器模式在开发中很少使用,
原型模式
同构造器模式功能一样,同样是对象的创建过程
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
getName(): string {
return this.name;
}
getAge(): number {
return this.age;
}
}
const person1 = new Person("李白", 18);
const person2 = new Person("杜甫", 20);
讲究方法复用,比如person1
和person2
的getName()
和getAge()
在内存中占用的时同一个空间
一般在函数原型链继承、class语法 中使用,通过原型可复用的特点,节省内存
工厂模式
创建某一类对象
enum Role {
ADMIN = 'admin',
AGENT = 'agent'
}
type Permission = Array<'read-new' | 'write-new' | 'delete-new'>
class User {
public role: Role
public permission: Permission
constructor(role: Role, permission: Permission) {
this.role = role
this.permission = permission
}
}
function userFactory(role: Role) {
if (role === Role.ADMIN) {
return new User(role, ['read-new', 'write-new', 'delete-new'])
}
if (role === Role.AGENT) {
return new User(role, ['read-new'])
}
}
const user = userFactory(Role.AGENT)
userFactory函数
就是User类
的创建工厂
这里还可以进一步优化,当前User类
在除userFactory函数
以外的地方也能直接实例化,这样让User类
实例化存在不可预知性
class User {
public role: Role
public permission: Permission
private constructor(role: Role, permission: Permission) {
this.role = role
this.permission = permission
}
static userFactory(role: Role) {
if (role === Role.ADMIN) {
return new User(role, ['read-new', 'write-new', 'delete-new'])
}
if (role === Role.AGENT) {
return new User(role, ['read-new'])
}
}
}
const user = User.userFactory(Role.AGENT)
User类
的创建变成了私有化,也就只能通过userFactory工厂函数
创建了
抽象工厂模式
创建实现了同一个抽象父类的类
enum Role {
ADMIN = 'admin',
AGENT = 'agent'
}
abstract class User {
public name: string
public role: Role
constructor(name: string, role: Role) {
this.name = name
this.role = role
}
abstract welcome(): void
}
class Admin extends User {
constructor(name: string) {
super(name, Role.ADMIN)
}
welcome() {
console.log(`Hello ${this.name}管理员`);
}
addAgent() {
// 添加代理
}
}
class Agent extends User {
constructor(name: string) {
super(name, Role.AGENT)
}
welcome() {
console.log(`Hello ${this.name}代理`);
}
}
function userAbstractFactory(role: Role): typeof Admin | typeof Agent {
if (role === Role.ADMIN) {
return Admin
}
if (role === Role.AGENT) {
return Agent
}
throw new Error('无对应的用户类型')
}
const ClassName = userAbstractFactory(Role.ADMIN)
const admin = new ClassName('李白')
工厂模式创建的对象因为属于一个类,所有属性和方法都是相同的;抽象工厂返回的类,每个类可以实现自己的不同的方法
简单来说,工厂模式是一个类根据不同情况创建一个对象;抽象工厂是在实现同一个抽象父类许多类中选择一个类
建造者模式
定义实体的表示过程
interface Task {
init(): void
run(): void
stop(): void
}
class Convert implements Task {
init() {
console.log("转换任务初始化");
}
run() {
return new Promise((resolve) => {
setTimeout(() => {
console.log("转换完成");
resolve(undefined)
}, 1000)
})
}
stop() {
console.log("结束转换");
}
}
class Split implements Task {
init() {
console.log("分割任务初始化");
}
run() {
return new Promise((resolve) => {
setTimeout(() => {
console.log("转换完成");
resolve(undefined)
}, 1500)
})
}
stop() {
console.log("结束分割");
}
}
class TaskBuilder {
private task: Task
constructor(task: Task) {
this.task = task
}
async build() {
this.task.init()
await this.task.run()
this.task.stop()
}
}
new TaskBuilder(new Convert()).build()
new TaskBuilder(new Split()).build()
工厂模式关心的是最后产生的什么实体,而建造者模式关心的是实体创建之后的表现过程
单例模式
限制一个类实例一个对象
class Model {
private $el!: HTMLDivElement
private constructor() {
this.render()
}
private render() {
const $el = document.createElement('div')
$el.innerText = '升级提示'
Object.assign($el.style, {
width: '200px',
height: '200px',
background: '#ccc',
display: 'none',
justifyContent: 'center',
alignItems: 'center',
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
})
document.body.appendChild($el)
this.$el = $el
}
show() {
this.$el.style.display = 'flex'
}
hide() {
this.$el.style.display = 'none'
}
private static instance: Model
public static createInstance() {
if (!this.instance) {
this.instance = new Model()
}
return this.instance
}
}
const model = Model.createInstance()
把类的创建权利交给createInstance
,限制只实例一个对象,可以看做一个特殊的工厂模式
结构型模式
装饰器模式
在不影响现有功能下,动态给实体添加功能
function pvLog(target: typeof Page, fieldName: keyof typeof Page) {
const originalFun = Reflect.get(target, fieldName) as { (...arg: any[]): any }
return {
value(...arg: any[]) {
console.log("pv统计");
originalFun.apply(this, arg)
}
}
}
class Page {
@pvLog
static toLogin() {
console.log("跳转到登录页面");
}
}
Page.toLogin()
适配器模式
让原本因不兼容而无法正常完成的工作,变的兼容并且完成
class TencentMap {
show() {
console.log("显示腾讯地图");
}
}
class BaiduMap {
display() {
console.log("显示百度地图");
}
}
interface MapContext {
render(): void
}
class TencentMapAdapter extends TencentMap implements MapContext {
render() {
this.show()
}
}
class BaiduMapAdapter extends BaiduMap implements MapContext {
render() {
this.display()
}
}
function render(map: MapContext) {
map.render()
}
render(new TencentMapAdapter())
render(new BaiduMapAdapter())
也可以用在处理前后端数据格式不一致情况,为数据转换提供适配器
代理模式
截取对实体的操作,由代理去操作实体
interface Movie {
name: string
price: number
}
class Star {
participateMovies: Array<Movie> = []
addMovie(movie: Movie) {
this.participateMovies.push(movie)
}
}
class Agent {
private star: Star = new Star()
addMovie(movie: Movie) {
if (movie.price < 100) {
throw new Error("价格太低")
}
this.star.addMovie(movie)
}
}
const agent = new Agent()
agent.addMovie({ name: "《星际穿越》", price: 1000 })
Proxy
专门用于代理模式
装饰器模式、适配器模式、代理模式的区别
装饰器模式 | 适配器模式 | 代理模式 | |
---|---|---|---|
功能 | 点缀原有功能 | 转换原有功能和数据,让原有的功能正常运行 | 代理原有功能和数据,给原有功能添加限制 |
是否影响原本功能 | 不影响 | 影响 | 不影响 |
去除之后,原有功能是否能正常运行 | 能 | 不能 | 能 |
和原有实体的关系 | 可以多个实体使用 | 可以用于多个实体 | 一个代理对应一个实体 |
外观模式
为多个子系统提供操作调度的实体,负责连接多个子系统
class Input {
render() {
return `
<div class="todo--header">
<input class="todo--input" type="text" placeholder="请输入事项内容"/>
<button class="todo--btn">添加</button>
</div>
`;
}
}
class List {
private data: Array<any>;
constructor(data: Array<any>) {
this.data = data;
}
render() {
return `
<ul class="todo--list">
${this.data
.map(
(item) => `
<li class="todo--item">
<span class="todo--content">${item.content}</span>
</li>
`
)
.join("")}`;
}
}
class TodoList {
private input: Input;
private list: List;
private data: Array<any> = [{
content: "hello world",
}];
constructor() {
this.input = new Input();
this.list = new List(this.data);
}
render() {
return `
<div>
${this.input.render()}
${this.list.render()}
</div>
`;
}
}
桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立变化
interface IAnimation {
show(el: HTMLDivElement): void
hide(el: HTMLDivElement): void
}
class Rotate implements IAnimation {
show(el: HTMLDivElement): void {
el.style.transform = 'rotate(360deg)'
}
hide(el: HTMLDivElement): void {
el.style.transform = 'rotate(0deg)'
}
}
class Scale implements IAnimation {
show(el: HTMLDivElement): void {
el.style.transform = 'scale(1)'
}
hide(el: HTMLDivElement): void {
el.style.transform = 'scale(0)'
}
}
class Toast {
message: string
animation: IAnimation
el!: HTMLDivElement
constructor(message: string, animation: IAnimation) {
this.message = message
this.animation = animation
this.render()
}
render() {
const div = document.createElement('div')
Object.assign(div.style, {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
padding: '10px 20px',
background: '#333',
color: '#fff',
borderRadius: '4px',
fontSize: '14px',
zIndex: '9999',
boxShadow: '0 0 3px rgba(0,0,0,.3)',
transition: 'all .3s ease-in-out',
})
div.innerText = this.message
document.body.appendChild(div)
this.el = div
setTimeout(() => {
this.animation.show(this.el)
})
}
destroy() {
this.animation.hide(this.el)
this.el.addEventListener('transitionend', () => {
document.body.removeChild(this.el)
})
}
}
const toast = new Toast('Hello World', new Scale())
setTimeout(() => {
toast.destroy()
}, 3000)
组合模式
处理树结构数据,以部分代表全部,操作部分也就操作的全部
只要一个类管理了一个数组,就可以称为组合模式
abstract class Context {
protected name: string;
constructor(name: string) {
this.name = name;
}
abstract scan(): void
}
class File extends Context {
constructor(name: string) {
super(name);
}
scan() {
console.log(`${this.name}文件扫描完毕`);
}
}
class Directory extends Context {
private children: Array<Context> = [];
constructor(name: string) {
super(name);
}
add(item: Context) {
this.children.push(item);
}
scan() {
console.log(`${this.name}文件夹扫描完毕`);
this.children.forEach((item) => item.scan());
}
}
let rootDirectory = new Directory('root');
let frontDirectory = new Directory('front');
let backDirectory = new Directory('back');
rootDirectory.add(frontDirectory);
const cssFile = new File('css');
const jsFile = new File('js');
frontDirectory.add(cssFile)
frontDirectory.add(jsFile)
rootDirectory.add(backDirectory);
rootDirectory.scan()
行为模式
观察者模式
实体一对多的依赖关系,以便当一个实体的状态发生改变时,所有依赖于它的实体都得到通知并自动更新
class Subject {
private observers: Observer[] = []
add(observer: Observer) {
this.observers.push(observer)
}
notify() {
this.observers.forEach(observer => observer.update())
}
remove(observer: Observer) {
this.observers = this.observers.filter(item => item !== observer)
}
}
class Observer {
private name: string
constructor(name: string) {
this.name = name
}
update() {
console.log(this.name + '触发update方法')
}
}
const subject = new Subject()
const observer1 = new Observer("观察者1号")
const observer2 = new Observer("观察者2号")
subject.add(observer1)
subject.add(observer2)
setTimeout(() => {
subject.notify()
}, 1000)
可以用于组件通信,或者数据回调
订阅发布模式
和观察者模式类似,但是订阅发布模式可以管理多个事件类型
class PubSub {
private events: Map<string, Array<Function>> = new Map()
on(eventName: string, callback: Function) {
if (!this.events.get(eventName)) {
this.events.set(eventName, [])
}
this.events.get(eventName)!.push(callback)
}
emit(eventName: string, ...args: any[]) {
const callbacks = this.events.get(eventName)
if (callbacks) {
callbacks.forEach(callback => callback(...args))
}
}
off(eventName: string, callback: Function) {
const callbacks = this.events.get(eventName)
if (callbacks) {
this.events.set(eventName, callbacks.filter(cb => cb !== callback))
}
}
}
const pubSub = new PubSub()
pubSub.on('test', () => {
console.log('test')
})
pubSub.on('test', () => {
console.log('test2')
})
pubSub.emit('test')
观察者模式和订阅发布模式区别
观察者模式 | 订阅发布模式 | |
---|---|---|
触发类型 | 一种事件 | 多种事件名称 |
模块模式
隔离私有和共有的属性和方法
let count = 0
const add = () => count++
const subtract = () => count--
export {
add,
subtract
}
命令模式
type CommandCode = 'log';
class Receiver {
log() {
console.log('Receiver 执行了');
}
}
class Command {
private receiver: Receiver;
constructor(receiver: Receiver) {
this.receiver = receiver;
}
execute(code: CommandCode) {
if (code === 'log') {
this.receiver.log();
}
}
}
class Invoker {
private command: Command;
constructor(command: Command) {
this.command = command;
}
invoke(code: CommandCode) {
this.command.execute(code);
}
}
const receiver = new Receiver();
const command = new Command(receiver);
const invoker = new Invoker(command);
invoker.invoke("log");
命令模式还可以与组合模式配套使用
type CommandCode = 'log';
class Receiver {
private name: string;
constructor(name: string) {
this.name = name;
}
log() {
console.log(`${this.name}的Receiver 执行了`);
}
}
class Command {
private receiver: Receiver;
constructor(receiver: Receiver) {
this.receiver = receiver;
}
execute(code: CommandCode) {
if (code === 'log') {
this.receiver.log();
}
}
}
class CommandCompose {
private commandList: Array<Command>;
constructor() {
this.commandList = [];
}
add(command: Command) {
this.commandList.push(command);
}
execute(code: CommandCode) {
this.commandList.forEach(command => {
command.execute(code);
})
}
}
class Invoker {
private commandCompose: CommandCompose;
constructor(commandCompose: CommandCompose) {
this.commandCompose = commandCompose;
}
invoke(code: CommandCode) {
this.commandCompose.execute(code);
}
}
// 命令1
const receiver1 = new Receiver("接受者1号");
const command1 = new Command(receiver1);
// 命令2
const receiver2 = new Receiver("接受者2号");
const command2 = new Command(receiver2);
const commandCompose = new CommandCompose();
commandCompose.add(command1)
commandCompose.add(command2)
const invoker = new Invoker(commandCompose);
invoker.invoke("log");
模板模式
子类实现抽象父类,并且完善抽象方法
abstract class Component {
constructor() {
this.init()
}
init() {
this.render();
}
abstract render(): void;
}
class Input extends Component {
render() {
console.log("input");
}
}
class Button extends Component {
render() {
console.log("button");
}
}
迭代器模式
遍历出实体中的元素
class Iterator<T> {
constructor(private data: Array<T>) {
this.data = data;
}
next() {
return {
value: this.data.shift(),
done: this.data.length === 0
}
}
}
let arrIterator = new Iterator([1, 2, 3, 4, 5]);
责任链模式
它允许一个请求通过一系列处理者(处理节点)进行传递,每个处理者都包含有对下一个处理者的引用,这样就会形成一个链表
abstract class Rule {
protected next: Rule | null = null;
abstract handle(value: string): boolean;
public check(value: string,): Boolean {
if (!this.handle(value)) {
return false
} else {
return this.next?.check(value) ?? true;
}
}
public setNext(rule: Rule) {
this.next = rule;
return rule
}
}
class EmptyRule extends Rule {
handle(value: string) {
return value !== ''
}
}
class MaxLengthRule extends Rule {
handle(value: string) {
return value.length < 10
}
}
class MinLengthRule extends Rule {
handle(value: string) {
return value.length > 5
}
}
let emptyRule = new EmptyRule();
let maxLengthRule = new MaxLengthRule();
let minLengthRule = new MinLengthRule();
//
emptyRule.setNext(maxLengthRule.setNext(minLengthRule))
let flog = emptyRule.check("你asdas好")
console.log(flog);
创建型、结构型、行为型的区别
创建型 | 结构型 | 行为型 | |
---|---|---|---|
实体对实体 | 单一实体 | 一对一 | 一对多 |
发挥的作用 | 为创建一个实体做准备 | 为已有实体修改属性 | 不同实体之间如何交流 |