前端 JS 设计模式之工厂模式、单例模式、适配器模式和装饰器模式

本文详细探讨了前端JavaScript中的四种设计模式:工厂模式用于封装对象创建,单例模式确保类只有一个实例,适配器模式解决接口不兼容问题,而装饰器模式则在不改变原有对象的基础上添加新功能。通过实例和代码展示,解释了这些模式在实际开发中的应用和遵循的设计原则。

一、工厂模式

  1. 工厂模式,将 new 操作单独封装。遇到 new 时,就要考虑是否该使用工厂模式。
  2. 对于工厂模式的理解,可以举例。你去购买汉堡,直接点餐、取餐,不会自己亲手做。商店要封装做汉堡的工作,做好直接给买者。
  3. 工厂模式的设计原则验证,构造函数和创建者分离,符合开放封闭原则。
  4. 工厂模式的代码,如下所示:
class  Product {
    constructor(name) {
        this.name = name
    }
    init() {
        alert('init')
    }
    fun1() {
        alert('fun1')
    }
    fun2() {
        alert('fun3')
    }
}

class Creator {
    create(name) {
        return new Product(name)
    }
}

// 测试
let creator = new Creator()
let p = creator.create('p1')
p.init()
p.fun1()

二、单例模式

  1. 单例模式,系统中被唯一使用,一个类只有一个实例。
  2. 对于单例模式,常见的示例,比如登录框、购物车、vuex 和 redux 中的 store 等等。
  3. 单例模式需要使用到 java 的特性 private。ES6 中没有,Typescript 除外,只能用 java 代码来演示 UML
    图的内容。
  4. 单例模式的设计原则验证,符合单一职责原则,只实例化唯一的对象。没法具体开放封闭原则,但是绝对不违反开放封闭原则。

单例模式的代码,如下所示:


class SingleObject {
    login() {
        console.log('login...')
    }
}
SingleObject.getInstance = (function () {
    let instance
    return function () {
        if (!instance) {
            instance = new SingleObject();
        }
        return instance
    }
})()

// 测试
let obj1 = SingleObject.getInstance()
obj1.login()
let obj2 = SingleObject.getInstance()
obj2.login()
console.log(obj1 === obj2)

单例模式与登录框的结合的代码,如下所示:

class LoginForm {
    constructor() {
        this.state = 'hide'
    }
    show() {
        if (this.state === 'show') {
            alert('已经显示')
            return
        }
        this.state = 'show'
        console.log('登录框已显示')
    }
    hide() {
        if (this.state === 'hide') {
            alert('已经隐藏')
            return
        }
        this.state = 'hide'
        console.log('登录框已隐藏')
    }
}
LoginForm.getInstance = (function () {
    let instance
    return function () {
        if (!instance) {
            instance = new LoginForm();
        }
        return instance
    }
})()

// 一个页面中调用登录框
let login1 = LoginForm.getInstance()
login1.show()
// login1.hide()

// 另一个页面中调用登录框
let login2 = LoginForm.getInstance()
login2.show()

// 两者是否相等
console.log('login1 === login2', login1 === login2)

三、适配器模式

  1. 适配器模式,旧接口格式和使用者不兼容,中间加一个适配转换接口。
  2. 对于适配器模式的理解,可以举例。比如在去香港旅游的时候,使用的插头和内地的插头不一样,需要使用转换器进行转换,才可以使用。
  3. 对于适配器模式的使用场景,封装旧接口,vue computed 等等。
  4. 适配器模式的设计原则验证,将旧接口和使用者进行分离,符合开放封闭原则。

适配器模式的代码,如下所示:

class Adaptee {
    specificRequest () {
        return '香港标准接口'
    }
}

class Target {
    constructor() {
        this.adaptee = new Adaptee()
    }
    request () {
        let info = this.adaptee.specificRequest()
        return `${info} - 转换器 - 内地标准插头`
    }
}

// 测试
let target = new Target()
let res = target.request()
console.log(res)

四、装饰器模式

  1. 装饰器模式,为对象添加新功能,不改变其原有的结构和功能。
  2. 对于装饰器模式的理解,可以举例。在手机上可以套上一个手机壳,不会影响手机的正常使用功能,可以给手机起到装饰的作用,并且保护手机不受到伤害。
  3. 对于装饰器模式的应用场景,比如 ES7 装饰器,core-decorators 等等。
  4. 装饰器模式的设计原则验证,将现有对象和装饰器进行分离,两者独立存在,符合开放封闭原则。

装饰器模式的代码,如下所示:


class Circle {
    draw () {
        console.log('画一个圆形')
    }
}


class Decorator {
    constructor (circle) {
        this.circle = circle
    }
    draw () {
        this.circle.draw()
        this.setRedBorder(circle)
    }
    setRedBorder(circle) {
        console.log('设置红色边框')
    }
}


// 测试代码
let circle = new Circle()
circle.draw()

let des = new Decorator(circle)
des.draw()


装饰器模式在 ES7 装饰器中应用的代码,如下所示:

function log(target, name, descriptor) {
  var oldValue = descriptor.value;

  descriptor.value = function() {
    console.log(`Calling ${name} with`, arguments);
    return oldValue.apply(this, arguments);
  };

  return descriptor;
}

class Math {
  @log
  add(a, b) {
    return a + b;
  }
}

const math = new Math();
const result = math.add(2, 4);
console.log('result', result);

装饰器模式在 core-decorators 中应用的代码,如下所示:


import { deprecate } from 'core-decorators';

class Person {
  @deprecate
  facepalm() {}

  @deprecate('We stopped facepalming')
  facepalmHard() {}

  @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
  facepalmHarder() {}
}

let person = new Person();

person.facepalm();

person.facepalmHard();

person.facepalmHarder();



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值