让前端飞TypeScript基础TypeScript 极简教程

TypeScript设计模式之单例、建造者、原型

2019-01-02  本文已影响49人  茶艺瑶

看看用TypeScript怎样实现常见的设计模式,顺便复习一下。
学模式最重要的不是记UML,而是知道什么模式可以解决什么样的问题,在做项目时碰到问题可以想到用哪个模式可以解决,UML忘了可以查,思想记住就好。
这里尽量用原创的,实际中能碰到的例子来说明模式的特点和用处。

单例模式 Singleton

特点:在程序得到生命周期只有一个全局的实例,并且不能再new出新的实例对象。
用处:在一些只需要一个对象存在的情况下,可以使用单列,比如Cache,ThreadPool,等。
可以看laravel 的 Request 类 在 Controller 中是怎么使用单列“注入”。
下面举个Cache的例子来看看单列模式:

class CacheT {

    public static readonly Instance: CacheT = new CacheT();

    private _items: { [key: string]: string } = {};

    private CacheT() { }


    set(key: string, value: string) {
        this._items[key] = value;
    }

    get(key: string): string {
        return this._items[key];
    }
}

console.log(CacheT.Instance.set('name', 'rainbow'));
console.log(CacheT.Instance.get('name'));

非常简单,和C#的基本一样,设置一个全局只读的Instance并且把构造函数设置为private就能确保单列的特点,这里不得不说.net的语言是很优雅的,不知道为什么当年为什么这么多人会吐槽asp.net...

以上代码再便于后得到的结果是

class CacheT {
    constructor() {
        this._items = {};
    }
    CacheT() {
    }
    set(key, value) {
        this._items[key] = value;
    }
    get(key) {
        return this._items[key];
    }
}
Cache.Instance = new Cache();
Cache.Instance.set('name', 'rainbow');
Cache.Instance.get('name');

可以看到TypeScript的静态实例Instance其实是直接加到了Cache本身上面,已经确保了不会再new实例化对象了。微软牛逼!!!

建造者模式 Builder

特点:一步一步来构建一个复杂对象,可以用不同组合或顺序建造出不同意义的对象,通常使用者并不需要知道建造的细节,通常使用链式调用来构建对象。

用处:当对象像积木一样灵活,并且需要使用者来自己组装时可以采用此模式,好处是不需要知道细节,调用方法即可,常用来构建如Http请求、生成器等。

注意:和工厂模式的区别,工厂是生产产品,谁生产,怎样生产无所谓,而建造者重在组装产品,层级不一样。

下面用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();

如果你在你的实际工作中,还需要XmlRequestBuilder,JsonRequestBuilder之类的话。RequestBuilder就应该设置为抽象类,那就可以用来隐藏细节和消除实现的依赖。

原型模式 Prototype

特点:不需要知道对象构建的细节,直接从对象上克隆出来。
用处:当对象的构建比较复杂时或者想得到目标对象相同内容的对象时可以考虑原型模式。
注意:深拷贝和浅拷贝。

JavaScript天生自带Prototype,通过Object.create就可以根据对象原型创建一个新的对象。

如果使typescript实现这个的话应该是以下代码,
使用泛型,不知道 泛型的同学可以搜索C#有关资料https://www.cnblogs.com/dotnet261010/p/9034594.html
解耦性会有所提高

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

这种情况就是想在创建属性也差不多的对象,原型就可以派上用场。
举个例子.
你用数据库读取出来的对象是{name:"xxx",age:18},
这时候你想在这个对象中创建一个新的对象并且添加一个新的属性。如:{name:'xxx',age:18,o:'xx'},
就可以使用到原型.
刚玩js的人同学都会犯一下错误。

let user = {name:"xxx",age:18};
let user1 = user;
user1.o = 'xx';

以为是改了user1实际user也同时改了。使用原型可以处理以上问题,当然在ES6你也可以使用Object.assin()合并的方式处理掉。自己百度OR直接看ElementUi的From Input 案列代码

最后如果你对文章感兴趣,您可以为小编点个赞
或扫个二维码请小编喝个咖啡


上一篇下一篇

猜你喜欢

热点阅读