泛型的定义
泛型, 软件开发过程中,我们不仅要创建一致的定义良好的api, 同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供十分灵活的功能。
在像C#和java这样的语言中,可以使用泛型来创建可重用的组件, 一个组件可以支持多种数据类型的数据。这样用户就可以以自己的数据类型来使用组件。
通俗理解,泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持
泛型函数
有一个需求: 传入指定的参数类型 返回这个指定的参数类型 比如 要求参数类型是 string 返回 string 要求参数类型是 number返回 number
// 只能返回string 的函数
function getData(val:string):string{
return val + "返回字符串";
}
// 只能返回number 的函数
function getData1(val:number):number{
return val; // 返回数字
}
这里用了两个函数去实习功能,如果还需要返回 bloolean 类型是不是还需要再添加多一个函数去实现, 这样实现的话会出现了代码的冗余
有人就会想到用any类型去实现功能,
function getData2(val:any):any{
return 123; // 返回number
}
getData2("string");
用any可以实现功能, 但是会出现这样的错误, 我传入string类型, 返回了number ,不符合要求, 并且使用any类型就是抛弃typeScript的初衷了,放弃了类型检查
使用泛型解决问题:泛型可以支持不特定类型, 实现要求传入类型和返回的类型一致
// T 表示泛型, 具体什么类型是调用的时候决定的
function getData<T>(val:T):T{
return val;
}
// 调用:
// number类型, 返回number 类型
getData<number>(100);
// string 类型
getData<string>("张三");
getData<boolean>(123); // 错误写法 定义Boolean类型,不能传入number类型的参数
如果要求函数返回必须为string类型的 泛型函数写法:
// 泛型函数, 指定返回string类型
function getData<T>(val:T):string{
return val + "val";
}
getData<number>(234);
getData<string>("张三");
通过这两个例子可以看出 泛型 T 代表的是一种数据类型, 具体是什么数据类型,就是要调用该方法的时候传入指定的类型来确定的 。
getData<T> getData<string> 该函数里面的所有T 都是泛型
泛型类
需求:比如有个最小的堆算法, 需要同时支持返回数字和字符串两种类型, 通过类的泛型来实现
// 不适用泛型类的写法
class MinClass{
public list:number[] = [];
add(num:number):void{
this.list.push(num);
}
min():number {
var minNum = this.list[0];
for(var i = 0; i < this.list.length; i++) {
if(minNum > this.list) {
minNum = this.list;
}
}
return minNum;
}
}
var m = new MinClass();
m.add(2);
m.add(50);
m.add(1);
console.log(m.min()); // 输出: 1
这个列子可以实现的是number类型的最小堆算法,对于类型校验,不能使用string的类型
看看 泛型类的实现
// 泛型类
class MinClass<T>{
public list:T[] = [];
add(num:T):void{
this.list.push(num);
}
min():T {
var minNum = this.list[0];
for(var i = 0; i < this.list.length; i++) {
if(minNum > this.list) {
minNum = this.list;
}
}
return minNum;
}
}
var m = new MinClass<number>(); // 实例化 类, 并且指定了泛型 的类型 为number
m.add(2);
m.add(50);
m.add(1);
console.log(m.min()); // 输出: 1
var s = new MinClass<string>();
s.add("n");
s.add("a");
s.add("z");
console.log(s.min()); // 输出: a 码值计算
使用泛型了, 可以写入number类型和string类型
--- 泛型类--- 进阶
要求:定义一个类,把类当作参数,来约束传入的数据类型
实现:定义一个user的类,这个类的作用是映射数据库字段, 然后定义个mysqlDb的类,用于操作数据库,然后把User类当作参数传入到mysqlDb执行
// 映射数据库字段的实体类
class User{
public username:string | undefined;
public pasword:string | undefined;
constructor() {
}
}
// 数据库操作类型
class MysqlDb{
// 添加数据
add(user:User):boolean{
return true;
}
// 删除数据
// 修改数据
// ----
}
var u = new User();
u.username = "张三";
u.pasword = "123";
var Db = new MysqlDb();
Db.add(u); // 把这个user添加到数据库中
这个 MysqlDb 可以执行 user类 的添加等操作, 同样的问题:这个MysqlDb 只能对user 类进行操作, 如果我还有其他的表:
class ArticleCate{
title:string | undefined;
desc:string | undefined;
status:number | undefined;
constructor() {
}
}
// 数据库操作类型
class MysqlDb{
// 添加数据
add(info:ArticleCate):boolean{
console.log(info);
return true;
}
// 删除数据
// 修改数据
// ----
}
var art = new ArticleCate();
art.status = 1;
art.desc = "国内新闻";
art.title = "国内";
var Db = new MysqlDb();
Db.add(art); // 把这个ArticleCate添加到数据库中
是不是这样就出现了代码的冗余, 有多个要操作的实体类,就要定义多个 MysqlDb 去实现
来看看泛型如何实现, 把 MysqlDb 就封装一次
// 映射数据库字段的实体类
class User{
public username:string | undefined;
public pasword:string | undefined;
constructor() {
}
}
class ArticleCate{
title:string | undefined;
desc:string | undefined;
status:number | undefined;
constructor() {
}
}
var art = new ArticleCate();
art.status = 1;
art.desc = "国内新闻";
art.title = "国内";
var DbArt = new MysqlDb<ArticleCate>(); // 直接实例化 mysqlDb
DbArt.add(art); // 把这个ArticleCate添加到数据库中
var user = new User();
user.username = "张三";
user.pasword = "24123";
var DbUser = new MysqlDb<User>();
DbUser.add(user); // 把这个User添加到数据库中
// DbUser.add(123); // 错误写法, 有类型校验
所以泛型, 不仅可以代表基本数据类型, 也可以是定义的类
泛型接口
先来看一个函数接口
// 函数接口
interface ConfigFn{
(val: string, val2: string):string;
}
// 实现接口
var getData:ConfigFn = function(val1:string, val2:string):string{
return val1 + val2;
}
var str:string = getData("张三", "李四");
console.log(str);
再来看看泛型接口
// 泛型函数接口
interface ConfigFn{
<T>(val: T, val2: T):T;
}
// 实现泛型函数接口
var getData:ConfigFn = function<T>(val1:T, val2:T):T{
return val1;
}
var str:string = getData<string>("张三", "李四");
console.log(str);
实现泛型接口的时候, 不指定泛型类型, 到调用的时候再指定类型
另外一种写法
// 泛型函数接口的另外一种写法
interface ConfigFn<T> {
(val: T, val2: T):T;
}
// 定义函数
function getData<T>(val1:T, val2:T):T{
return val1;
}
// 实现接口, 并且指定类型
var myGetData:ConfigFn<string> = getData;
myGetData("张三", "李四");
注意: 实现泛型接口,本身也要是一个泛型
有了泛型, 调用方法的时候,同样的代码,可供多个类型使用,大大的扩展了代码的复用性
使用 类,接口,泛型, 实现SQL底层封装
sql 数据库类的简单功能有: 查询, 添加, 修改, 删除 ,先从这四个功能起封装库类, 先定义一个泛型接口
// 定义基础接口
interface DBI<T>{
add(info:T): boolean;
update(info:T,id:number): boolean;
delete(id:number): boolean;
get(id:number): any[];
}
简单实现接口, 注意: 要实现泛型接口, 这个类也是必须是泛型类
// 定义一个操作mysql数据库类, 实现接口, 注意要实现泛型接口, 这个类也是泛型类
class MysqlDb<T> implements DBI<T> {
constructor() {
// 数据库建立连接-------
}
add(info: T): boolean {
throw new Error("Method not implemented.");
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
throw new Error("Method not implemented.");
}
}
// 实现sqlserver 的数据库类
class SqlserverDb<T> implements DBI<T> {
constructor() {
// 数据库建立连接-------
}
add(info: T): boolean {
throw new Error("Method not implemented.");
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
throw new Error("Method not implemented.");
}
}
实现mysql数据类操作User数据表,, 使用泛型, 把类当作参数来约束方法
// 定义实体类, 映射数据库表的类
class User{
id: number | undefined;
userName:string | undefined;
password:string | undefined;
}
var user = new User();
user.id = 1;
user.userName = "tom";
user.password = "12345678";
// 实现user类的数据库操作
var UserMysql = new MysqlDb<User>();
来源:https://www.cnblogs.com/yangWanSheng/p/15417092.html |