设计模式的重要性毋需再言。本文将讲述,如何用TypeScript实现生成器模式
欢迎来到 TypeScript 中的设计模式系列,它介绍了使用TypeScript进行Web开发的一些有用的设计模式。
系列文章如下:
- 设计模式:(Strategy Pattern)策略模式
- 设计模式:(Chain of Responsibility Pattern)责任链模式
- 适配器模式: (Adapter Pattern) 适配器模式
- 设计模式:(Template Method Pattern)模板方法模式
- 设计模式:(Observer Pattern) 观察者模式
生成器模式 能将一个复杂的对象分解成相对简单的部分,然后根据不同的需要分别创建,最终构建出复杂的对象。
例如:
class User {
constructor(
username:string,
sex:string,
age:number,
photo:string,
email:string
){}
}
上面的代码中,我们定义了一个User类,通过此类,可以创建User实例。
const user = new User("kevin", "male", "35", "https://qq.com", "kevin@qq.com")
虽然我们可以成功的创建一个User实例,但注意到初始化User时,需要进行复杂的初始化工作,如需要一次性传入足够多的参数来构造实例。
那有没有更好的方法呢?解决方案是使用生成器设计模式。
如:
class UserBuilder {
username: string;
sex: string;
age: number;
photo: string;
email: string;
setUserName(name: string) {
this.username = name;
return this;
}
setSex(sex: string) {
this.sex = sex;
return this;
}
setAge(age: number) {
this.age = age;
return this;
}
setPhoto(photo: string) {
this.photo = photo;
return this;
}
setEmail(email: string) {
this.email = email;
return this;
}
build() {
return new User(this.username, this.sex, this.age, this.photo, this.email);
}
}
在 UserBuilder 中,我们定义了几个 setXXX方法和一个build方法。该setXXX方法用于设置实例属性的值,而build方法用于实例化User类
此时创建一个user类的实例变成如下:
const user = new UserBuilder()
.setUserName('kevin')
.setSex('male')
.setAge(35)
.setPhoto('https://qq.com')
.setEmail('kevin@qq.com');
看完上面的例子,你会发现builder模式并不复杂。在实际的 TypeScript 项目中,我们可以使用builder-pattern库来有效地使用 builder 模式。
基本用法
interface UserInfo {
id:number
userName: string;
email: string;
}
const userInfo = Builder<UserInfo>()
.id(1)
.userName('foo')
.email('foo@bar.baz')
.build();
与模板对象使用
const defaultUserInfo: UserInfo = {
id: 1,
userName: 'foo',
email: 'foo@bar.baz'
};
const modifiedUserInfo = Builder(defaultUserInfo)
.id(2)
.build();
与类对象使用
class UserInfo {
id!: number;
userName!: string;
email!: string;
}
const userInfo = Builder(UserInfo) // note that ( ) is used instead of < > here
.id(1)
.userName('foo')
.email('foo@bar.baz')
.build();
在数据查询的场景中,我们经常会看到生成器模式。比如构造sql或者elasticsearch查询条件,这里我们以一个bodybuilder(An elasticsearch query body builder)库为例来看看它的基本用法
bodybuilder()
.query('match', 'message', 'this is a test')
.filter('term', 'user', 'kimchy')
.filter('term', 'user', 'herald' )
.orFilter('term', 'user', 'johnny')
.notFilter('term', 'user', 'cassie')
.aggregation('terms', 'user')
.build()
最后总结一下builder模式的使用场景:
- 当一个类有超过 4 个构造函数参数,并且其中一些参数是可选的,考虑使用生成器模式。