创建型
创建型设计模式(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正常。
单例模式
单例模式是一种创建型设计模式,其目的是确保某个类只有一个实例,并且提供一个全局的访问点。可以避免在系统中出现多个实例,减少资源开销,同时保证数据的唯一性和全局状态的管理。
单例模式的关键
- 唯一实例:保证一个类只有一个实例。
- 全局访问点:提供一个访问该实例的全局访问点。
- 延迟实例化:实例第一次使用时才需要实例化。
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);
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()
运行结果
抽象工厂模式
抽工厂模式体统一个接口来创建一些列相关或依赖对象,而无需指定它们的具体类
抽象工厂模式的结构
- 抽象工厂:声明创建一组相关对象的接口。
- 具体工厂:实现抽象工厂的接口,创建具体产品对象。
- 抽象产品:为每种产品声明接口
- 具体产品:实现抽象接口的具体类
- 客服端:使用工厂接口创建产品对象
//假设现在有两个生产宝马和奔驰的工厂
//假设一个车只由车身和车轮组成
//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()
运行结果
与工厂模式的区别
创建对象的复杂性:
- 工厂模式用于创建单一对象,主要关注对象的创建过程。
- 建造者模式用于创建复杂对象,关注构建过程的步骤和顺序。
对象类型:
- 工厂模式根据条件创建不同类型的对象。
- 建造者模式通过逐步构建的方式创建复杂对象。
客户端控制:
- 工厂模式客户端通过选择具体工厂来控制对象创建。
- 建造者模式客户端通过指挥者来控制对象的构建过程。