当前位置: 首页 > news >正文

Typescript高级: 深入理解工厂函数类型

工厂函数类型

  • 代表任意一个类的构造函数【等价JS的构造函数】的函数类型
  • 在TS中无法使用 new 来直接实例化一个 function
  • 现在通过几个小case来测试下这种类型

1 )模拟一个动物的行为接口(简单)

  • 创建几个实现了这个接口的类来展示接口的用途和如何使用它

  • 下面是一个关于动物及其行为(以吃东西为例)的TypeScript示例:

    // 定义一个动物行为接口,其中包含一个eat方法
    interface AnimalBehavior {eat: (...args: any) => any;
    }// 实现AnimalBehavior接口的Dog类
    class Dog implements AnimalBehavior {name: string;constructor(name: string) {this.name = name;}// 实现eat方法,模拟狗吃骨头的行为eat(food: string): void {console.log(`${this.name} the dog is eating ${food}.`);}
    }// 实现AnimalBehavior接口的Cat类
    class Cat implements AnimalBehavior {name: string;constructor(name: string) {this.name = name;}// 实现eat方法,模拟猫吃鱼的行为eat(food: string): void {console.log(`${this.name} the cat is enjoying ${food}.`);}
    }// 使用示例
    function feedAnimal(animal: AnimalBehavior, food: string): void {animal.eat(food);
    }// 创建Dog和Cat实例
    const myDog = new Dog("Rex");
    const myCat = new Cat("Whiskers");// 喂食
    feedAnimal(myDog, "a bone"); // 输出: Rex the dog is eating a bone.
    feedAnimal(myCat, "fish"); // 输出: Whiskers the cat is enjoying fish.
    
  • 在这个示例中,定义了一个AnimalBehavior接口,它要求实现类必须有一个名为eat的方法 eat: (...args: any) => any;

  • 注意,这里还没有涉及任何的工厂函数类型

  • 该方法可以接受任意数量的参数并返回任意类型

  • 接着,创建了两个类Dog和Cat,它们都实现了AnimalBehavior接口,并分别实现了eat方法来模拟各自的进食行为

  • 最后,我们定义了一个feedAnimal函数,它接受任何实现了AnimalBehavior接口的对象以及食物类型作为参数

  • 以此展示如何通过接口来规范和使用不同类型的对象

2 )模拟一个简单的银行贷款服务场景

  • 定义一个CommercialBank类来表示银行
  • 这个类包含了银行的基本信息,如地址和名称,并提供了一个贷款方法
    class CommercialBank {public address: string;public name: string;constructor(name: string, address: string) {this.address = address;this.name = name;}loan(): void {console.log(`${this.name} 银行提供贷款服务`);}
    }type Cst<T> = new (...args: any[]) => T; // 工厂函数类型function createBank<T extends CommercialBank>(BankClass: Cst<T>, name: string, address: string): T {return new BankClass(name, address);
    }class SavingsBank extends CommercialBank {saveMoney(): void {console.log("储蓄银行提供存款服务");}
    }const savingsBank = createBank<SavingsBank>(SavingsBank, "储蓄银行", "上海");
    savingsBank.loan(); // 输出: 储蓄银行提供贷款服务
    savingsBank.saveMoney(); // 输出: 储蓄银行提供存款服务
    
  • 在TypeScript中,通过new关键字,我们可以实例化一个类
  • 但直接new一个普通函数是不允许的,因为TypeScript严格区分了函数和构造函数
  • 为了表示一个可以被new操作符使用的构造函数类型,我们引入了构造函数类型constructor
  • 它是一个特殊的类型别名,表示可以接受任意参数并返回一个特定类型实例的函数
  • type Cst<T> = new (...args: any[]) => T 这条语句,作为工厂函数类型的示例,而且是一个泛型工厂类型

构造函数类型与工厂函数类型的示例


1 )构造函数类型

  • 构造函数类型主要指代那些用于创建类实例的函数。
  • 在TypeScript中,当你定义一个类时,实际上就是在定义一个构造函数类型。构造函数通过new关键字被调用,用于初始化新创建的对象并分配内存。
  • 构造函数类型关心的是如何创建和初始化一个特定类的实例
    class Animal {name: string;constructor(name: string) {this.name = name;}
    }
    
  • 这里Animal就是构造函数类型
  • 它接收一个string参数并返回Animal类型的实例

2 )工厂函数类型

  • 工厂函数类型是一种设计模式的体现,其目的是提供一个统一的接口用于创建一系列相关或依赖对象,而不需要向客户端暴露创建逻辑
  • 工厂函数通常返回一个对象实例,但与构造函数不同,它不一定要使用new关键字
  • 工厂函数的优势在于它可以根据输入参数的不同,返回不同类型的对象,提供更大的灵活性
  • 在TypeScript中,可以通过定义一个返回构造函数类型的函数来实现工厂函数类型,比如:
    // 这里是 简单工厂类型,不是泛型工厂类型
    type AnimalConstructor = new (name: string) => Animal;function getAnimalFactory(animalType: string): AnimalConstructor {if (animalType === 'dog') {return Dog; // 假设Dog是另一个实现了Animal的类} else if (animalType === 'cat') {return Cat; // 同理,Cat也是实现了Animal的类} else {throw new Error('Unsupported animal type');}
    }const dogFactory = getAnimalFactory('dog');
    const myDog = new dogFactory('Rex'); // 使用工厂函数得到的构造函数创建对象
    

总结

  • 尽管构造函数类型和工厂函数类型在实际应用中可以紧密相连
  • 它们的核心区别在于:
    • 构造函数类型专注于初始化单一类型实例的细节
    • 工厂函数类型则提供了一个更高层次的抽象,根据条件或参数决定创建哪种类型的实例,增加了灵活性和解耦
    • 因此,它们虽有联系,但在设计意图和应用场景上有所区分

相关文章:

  • 【计算机毕业设计】基于SSM++jsp的实验室耗材管理系统【源码+lw+部署文档】
  • Day02:LeedCode977. 有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II
  • 《Qt》使用Windeployqt发布程序
  • 【yolo 项目】
  • el-radio-group 选择一个,全部选中 解决方案
  • [蓝桥杯 2020 省 A1] 超级胶水
  • 顶顶通呼叫中心中间件-自动外呼输入分机号(比如隐私号)(mod_cti基于FreeSWITCH)
  • 信息泄露--注意点点
  • AI大模型应用开发实践:3.使用 tiktoken 计算 token 数量
  • SQL 面试系列(一)【留存率问题】
  • 【论文笔记】Attention is All You Need(NIPS’17)
  • 递增链表去重
  • 【WEEK13】 【DAY3】Shiro第三部分【中文版】
  • SSL证书制作及nginx部署
  • 局域网传文件怎么操作?轻松实现文件共享!
  • php的引用
  • 3.7、@ResponseBody 和 @RestController
  • Python 反序列化安全问题(二)
  • Python_网络编程
  • Sass 快速入门教程
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 构建工具 - 收藏集 - 掘金
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 检测对象或数组
  • 前端面试之CSS3新特性
  • 使用权重正则化较少模型过拟合
  • 协程
  • 应用生命周期终极 DevOps 工具包
  • Mac 上flink的安装与启动
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #《AI中文版》V3 第 1 章 概述
  • (03)光刻——半导体电路的绘制
  • (11)MATLAB PCA+SVM 人脸识别
  • (2)MFC+openGL单文档框架glFrame
  • (2020)Java后端开发----(面试题和笔试题)
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (十三)Maven插件解析运行机制
  • (一)Java算法:二分查找
  • (转)人的集合论——移山之道
  • ./和../以及/和~之间的区别
  • .NET Core 项目指定SDK版本
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .net Signalr 使用笔记
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .net 微服务 服务保护 自动重试 Polly
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .vimrc 配置项
  • @Bean注解详解
  • @NestedConfigurationProperty 注解用法
  • [ C++ ] STL---string类的模拟实现