看看用TypeScript怎样实现常见的设计模式,顺便复习一下。
下面用TypeScript写一个Cache来看看单例模式:
class Cache{ public static readonly Instance: Cache = new Cache(); private _items: {[key: string]: string} = {}; private Cache(){ } set(key: string, value: string){ this._items[key] = value; console.log(`set cache with key: '${key}', value: '${value}'`); } get(key: string): string{ let value = this._items[key]; console.log(`get cache value: '${value}' with key: '${key}'`); return value; } } Cache.Instance.set('name', 'brook'); Cache.Instance.get('name');输出:
set cache with key: 'name', value: 'brook' get cache value: 'brook' with key: 'name'很简单, 和C#基本一样, 设置一个全局只读的Instance并且把构造函数设为private,这样就确保了单例的特点。 可能有人有疑问:静态Instance在C#里能确保只有一个是CLR的功劳,这里每次访问Instance会不会重新new一个呢? 带着疑问来看看上面代码编译成JavaScript ES6的结果:
class Cache { constructor() { this._items = {}; } Cache() { } set(key, value) { this._items[key] = value; console.log(`set cache with key: '${key}', value: '${value}'`); } get(key) { let value = this._items[key]; console.log(`get cache value: '${value}' with key: '${key}'`); return value; } } Cache.Instance = new Cache(); Cache.Instance.set('name', 'brook'); Cache.Instance.get('name');可以看到TypeScript的静态实例Instance其实是直接加到了Cache本身上面,当然也就确保了不会再new出新的来。
下面用TypeScript写一个Http的RequestBuilder来看看建造者模式:
enum HttpMethod{ GET, POST, } class HttpRequest {} //假设这是最终要发送的request class RequestBuilder{ private _method: HttpMethod; private _headers: {[key: string]: string} = {}; private _querys: {[key: string]: string} = {}; private _body: string; setMethod(method: HttpMethod): RequestBuilder{ this._method = method; return this; } setHeader(key: string, value: string): RequestBuilder{ this._headers[key] = value; return this; } setQuery(key: string, value: string): RequestBuilder{ this._querys[key] = value; return this; } setBody(body: string): RequestBuilder{ this._body = body; return this; } build(): HttpRequest { // 根据上面信息生成HttpRequest } } let getRequest = new RequestBuilder() .setMethod(HttpMethod.GET) .setQuery('name', 'brook') .build(); let postRequest = new RequestBuilder() .setMethod(HttpMethod.POST) .setHeader('ContentType', 'application/json') .setBody('body') .build();上面RequestBuilder可以根据传进来的参数不同来构建出不同的HttpReqeust对象,这样使用者就可以按照自己需求来生成想要的对象。
这里有个问题是RequestBuilder需不需要抽象出来,个人觉得要看情况而定。 首先是保持简单,不去套UML,只是一个简单的构造功能给内部使用也没必要抽象来增加代码复杂度,但如果业务上这个Builder是封装在一个库里面并且要对外提供服务,那还是需要一个抽象来隐藏细节,消除对实现的依赖。 并且如果业务上还需要不同的RequestBuilder,比如说XmlRequestBuilder JsonRequestBuilder之类,那就更需要一个抽象了。
JavaScript对这个应该是太了解了,天生就有Prototype,通过Object.create就可以根据对象原型创建一个新的对象。
class Origin{ name: string } let origin = new Origin(); origin.name = 'brook'; let cloneObj = Object.create(origin); console.log(cloneObj.name); // brook不过还是用代码简单实现一下原型模式
interface Clonable<T>{ clone(): T; } class Origin implements Clonable<Origin>{ name: string; clone(): Origin{ let target = new Origin(); target.name = this.name; return target; } } let origin = new Origin(); origin.name = 'brook'; let cloneObj = origin.clone(); console.log(cloneObj.name); // brook实现Clonable接口的都具有Clone功能,通过Clone功能就可以实现对象的快速复制,如果属性很多,想另外创建属性值也差不多相同的对象,原型就可以派上用场。 当然,还是要注意深拷贝和浅拷贝的问题,上面的代码只有string,所以浅拷贝没有问题,如果有对象就需要注意浅拷贝是否能满足要求。