js设计模式之创建型模式(一)

创建型

创建型设计模式(Creational Design Patterns)关注对象的创建过程。这些模式通过封装创建逻辑,减少直接实例化对象的复杂性,提高代码的灵活性和可维护性,使得对象的创建过程变得更加适应各种复杂的场景需求。

原型模式

当某个对象需要重复创建时,里面的方法也会被重复创建,这样大大的增加了内存开销,可以把方法放在原型上,这样就可以多对象的同一个方法只占用一块内存。

  • 目的:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
  • 应用场景:需要大量创建相同或相似对象时,尤其是创建成本高昂或复杂的对象。
  • 实现:通过实现一个克隆方法来复制现有实例。

当一个对象被new时

  • 一个新的空对象被创建:person1
  • 这个新对象的 __proto__ 属性被设置为 Person.prototype
  • Person 构造函数以 person1 为上下文被调用(即 this 指向 person1
function Person (name){
    this.name = name
    Person.prototype.say = function (){
        console.log('我叫',this.name);
    }
}
// console.log(Person);
function Doctor (name){
    Doctor.prototype = Person.prototype
    //一般建议把下面段代码写在外面,这里只是论述原型实例之间的关系,才这样写
    Doctor.prototype.work = function (){
        console.log('我会做手术');
    }
}
//写在外面
//Doctor.prototype.work = function (){
   //     console.log('我会做手术');
 //   }
const Person1 = new Person('李四')
console.log(Person1);
Person1.say()
const person2 = new Person('张三')
console.log(person2);
const Doctor1 = new Doctor('李四')
console.log(Doctor1);
// Doctor1.work()
const Doctor2 = new Doctor('李四')
Doctor2.work()
console.log(Doctor2);

运行结果

在这里插入图片描述

当new Person(‘李四’) 创建时,首先会让person1 的_proto_会指向原型 Person,然后执行构造函数Person,向原型中新加了一个say方法,此时调用Person1.say()是在原型上的say方法故可以调用成功

Doctor1,当 new Doctor(‘李四’)时,首先Doctor1的_proto_指向Doctor,然后执行构造函数,让Doctor的原型链指向Person,向Doctor原型加一个work方法,实际上是添加在Person原型上的。当时执行Doctor1.work时候会报错,因为Doctor原型上没有work方法。Doctor2 ,当 new Doctor(‘李四’),时候 让Doctor2的_proto_指向Doctor,但Doctor是指向Person的,而Person的原型又是指向Object,故他们的_proto_都是指向Object,所以Doctor2的原型是Person,而Person原型上又有work方法,故此时调用Doctor2.work正常。

prototype
constructor
_proto_
_proto_
Docter构造函数
Docter原型
Docter1
Docter2
Person原型 say方法 work方法
Object原型

单例模式

单例模式是一种创建型设计模式,其目的是确保某个类只有一个实例,并且提供一个全局的访问点。可以避免在系统中出现多个实例,减少资源开销,同时保证数据的唯一性和全局状态的管理。

单例模式的关键

  • 唯一实例:保证一个类只有一个实例。
  • 全局访问点:提供一个访问该实例的全局访问点。
  • 延迟实例化:实例第一次使用时才需要实例化。
function Log (date){
    
    if(!Log.prototype.instance){
        Log.prototype.instance = this
    }
    Log.prototype.instance.date = date
    return Log.prototype.instance
}
const date1 = new Log('2-1')
const date2 = new Log('2-2')
console.log(date1);
console.log(date2);
_proto_
instance
constructor
prototype
data1
Log原型
Log构造函数
data2

data1,此时new Log(‘2-1’),代表创建一个该实例,让_proto_指向Log原型,执行构造函数Log,此时Log原型没有instance,让instance 指向该实例this,然后赋值,返回Log原型上的instance,也就是data1。data2,当new Log(‘2-2’),时,让_proto_指向Log原型,执行构造函数Log,此时Log原型上有instance,故直接赋值,返回Log原型上的instance,实际上也是data1,故打印date都为 2-2

工厂模式

工厂模式通过定义一个创建对象的接口,让子类决定实例化那个类,这样可以使延迟实例化子类

工厂方法模式的关键

  • 创建接口:定义一个用于创建对象的接口,工厂模式将对象延迟实例化到子类
  • 延迟实例化:子类实现工厂方法来创建具体的产品对象

工厂模式的结构

  • 产品接口:定义产品的公共接口。
  • 具体产品:实现产品接口的具体类。
  • 工厂接口:定义工厂方法,用于创造产品。
  • 具体工厂:实现工厂的方法,返回具体产品实例。
//假设现在我想创建一个生产动物的工厂
function createAnimal(name){
    switch(name){
        case 'Cat': return new Cat()
        case 'Dog':return new Dog()
        case 'Bird':return new Bird()
        default:console.error(name+'参数错误');;return new Error('参数错误')
    }
}
//产品具体实现
function Cat(){
    this.name = '猫'
}
Cat.prototype.say = function (){
    console.log(`我是一只${this.name},我会喵喵~~`);
}
function Dog(){
    this.name = '狗'
}
Dog.prototype.say = function (){
    console.log(`我是一只${this.name},我会旺旺~~`);
}
function Bird(){
    this.name = '鸟'
}
Bird.prototype.say = ()=>{
    console.log(`我是一只${this.name},我会鸡鸡~~`);
}
//创造产品
const cat = createAnimal('Cat')
const dog = createAnimal('Dog')
const bird = createAnimal('Bird')
const tiger = createAnimal('tiger')
cat.say()
dog.say()
bird.say()

运行结果

在这里插入图片描述

createAnimal
Cat
Dog
Bird

抽象工厂模式

抽工厂模式体统一个接口来创建一些列相关或依赖对象,而无需指定它们的具体类

抽象工厂模式的结构

  • 抽象工厂:声明创建一组相关对象的接口。
  • 具体工厂:实现抽象工厂的接口,创建具体产品对象。
  • 抽象产品:为每种产品声明接口
  • 具体产品:实现抽象接口的具体类
  • 客服端:使用工厂接口创建产品对象
//假设现在有两个生产宝马和奔驰的工厂
//假设一个车只由车身和车轮组成
//1.定义抽象产品方法
//车身的抽象方法
class AbstractCarBody{
    constructor(brand){
        //品牌名称
        if(!brand) throw new Error('必须传入品牌名称')
        this.brand = brand
        if(new.target == AbstractCarBody){
            throw new Error('不能创建抽象类 AbstractCarBody')
        }
    }
    CarBody(){
        throw new Error("你必须实现CarBody方法")
    }
}
//车轮的抽象方法
class AbstractWheel{
    constructor(brand){
         //品牌名称
         if(!brand) throw new Error('必须传入品牌名称')
            this.brand = brand
            if(new.target == AbstractWheel){
                throw new Error('不能创建抽象类 AbstractWheel')
            }
    }
    wheel(){
        throw new Error("你必须实现wheel方法")
    }
}

//2.抽象产品方法具体实现
class BMWCarBody extends AbstractCarBody{
    constructor(color){
        super('BMW')
        this.color = color

    }
    CarBody(){
        return `我的${this.brand}的车身,我的颜色是${this.color}`
    }
}
class BenzCarBody extends AbstractCarBody{
    constructor(color){
        super('Benz')
        this.color = color
    } 
    CarBody(){
        return `我是${this.brand}的车身,我的颜色是${this.color}`
    }
}
class BMWWheel extends AbstractWheel{
    constructor(color){
        super('BMW')
        this.color = color
    }
    wheel(){
        return `我是${this.brand}的轮子,我的颜色是${this.color}`
    }
}
class BenzWheel extends AbstractWheel{
    constructor(color){
        super('Benz')
        this.color = color
    }
    wheel(){
        return `我是${this.brand}的轮子,我的颜色是${this.color}`
    }
}

//3.抽象工厂
class AbstractFactory{
     constructor(){
        if(!new.target == AbstractFactory)throw new Error('不能创建 AbstractFactory 类')
     }
    createProduct(type){
      switch(type){
        case 'CarBody':return this.createCarBody()
        case 'wheel' : return this.createWheel()
        default:throw new Error('参数错误')
      }  
    }
    createCarBody(){
        throw new Error('createCarBody 方法必须被重写')
    }
    createWheel(){
        throw new Error('createWheel 方法必须被重写')
    }
    assemble(){
        throw new Error('assemble 方法必须被重写')
    }
}
//4.具体工厂实现
class BMWFactory extends AbstractFactory{
    createCarBody(){
        return new BMWCarBody('黑色')
    }
    createWheel(){
        return new BMWWheel('蓝色')
    }
    assemble(){
        this.CarBody=this.createCarBody()
        this.wheel=this.createWheel()
        return this.CarBody.CarBody()+this.wheel.wheel()
    }

}

class BenzFactory extends AbstractFactory{
    
    createCarBody(){
        return new BenzCarBody('粉色')
    }
    createWheel(){
        return new BenzWheel('紫色')
    }
    assemble(){
        this.CarBody=this.createCarBody()
        this.wheel=this.createWheel()
        return this.CarBody.CarBody()+this.wheel.wheel()
    }
}
//5.客户端
function clientCode(factory){
    factory.createCarBody()
    factory.createWheel()
    console.log(factory.assemble());
}
const bmwFactory = new BMWFactory()
const benzFactory = new BenzFactory()
clientCode(bmwFactory)
clientCode(benzFactory)
//需要一个奔驰的轮胎 
const a = benzFactory.createProduct('wheel')
console.log(a.wheel());

运行结果

在这里插入图片描述

建造者模式

建造者模式是一个将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。建造者模式通常用于需要创建的对象包含多个部分,并且这些部分的构建过程相对复杂的场景。

建造模式的结构

  • 产品:表示被构建的复杂对象
  • 建造者:定义构建产品各个部分的接口
  • 具体建造者:实现builder接口,构建和装配各个部分
  • 指挥者:负责管理建造过程,指定建造的步骤和顺序
  • 客户端:通过指挥者构造复杂对象
//1.产品
class BOOK {
    constructor(){
        this.book = []
    }
    page(content){
        return  `************\n************\n*****${content}****\n************\n************\n`
    }
    addPage(page){
        this.book.push(page)
    }
    showBook(){
        for(let i =0 ; i<this.book.length;i++)console.log(this.book[i]);
    }
}
//2.定义建造者接口
class Builder{
    //添加目录
    addCataLog(){
        throw new Error('必须实现 addCataLog方法')
    }
    //添加内容
    addContent(){
        throw new Error('必须实现 addContent 方法')
    }
    //添加结尾
    addEnd(){
        throw new Error('必须实现 addEnd 方法')
    }
    //交付产品
    getResult(){
        throw new Error('必须实现 getResult 方法')
    }
}
//3.具体实现建造者
class BookBuilder extends Builder{
    constructor(){
        super()
        this.product = new BOOK()
    }
    addCataLog(){
        this.product.addPage(this.product.page('目录'))
    }
    addContent(content){
        this.product.addPage(this.product.page(content))

    }
    addEnd(){
        this.product.addPage(this.product.page('结尾'))
    }
    getResult(){
        return this.product
    }
}
//4.定义指挥者
class Director{
    setBuilder(builder){
        this.builder = builder
    }
    construct(){
        this.builder.addCataLog()
        this.builder.addContent('内容1')
        this.builder.addContent('内容2')
        this.builder.addEnd()
    }
}
//5.客户端
const  director =new Director()
const builder = new BookBuilder()
director.setBuilder(builder)
director.construct()
const product = builder.getResult()
product.showBook()

运行结果
在这里插入图片描述

指挥者
建造者
任务1
任务2
任务...
产品

与工厂模式的区别

创建对象的复杂性

  • 工厂模式用于创建单一对象,主要关注对象的创建过程。
  • 建造者模式用于创建复杂对象,关注构建过程的步骤和顺序。

对象类型

  • 工厂模式根据条件创建不同类型的对象。
  • 建造者模式通过逐步构建的方式创建复杂对象。

客户端控制

  • 工厂模式客户端通过选择具体工厂来控制对象创建。
  • 建造者模式客户端通过指挥者来控制对象的构建过程。

参考文献

js 设计模式(23种)_js设计模式-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值