TypeScript设计模式之职责链、状态

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

职责链模式 Chain of Responsibility

特点:可以让一个请求被不同的对象处理多次,请求像经过管道一样, 一路上都可以被拦下处理。

用处:当请求需要被链式处理时,可以考虑职责链模式,比如事件的冒泡,WebApi的管道Handler等。

注意:链的实现。

WebApi的handler可能大家有用过,对发出去的请求和请求回来的数据都可以用自定义handler在发出前或最终回来前进行处理,非常方便,下面用TypeScript来简单实现一个HttpHandler:

先建立一个抽象Handler类,包含一个发送请求的sendReqeust以及用来链式处理的innerHandler:

abstract class HttpHandler{

    constructor(protected innerHandler: HttpHandler){}

    async sendRequest(req: string): Promise<string>{
        if(this.innerHandler){
            return await this.innerHandler.sendRequest(req);
        } else {
            let res = `response`;
            console.log(res);
            return res;
        }   
    }
}

实现第一个Handler类:

class FirstHttpHandler extends HttpHandler{
    
    async sendRequest(req: string): Promise<string>{

        req = `<req1>${req}</req1>`; // 把请求包一下
        console.log(req);

        let res = await super.sendRequest(req);

        res = `<res1>${res}</res1>`; // 把结果包一下
        console.log(res);

        return res;
    }
}

再实现第二个Handler类:

class SecondHttpHandler extends HttpHandler{
    
    async sendRequest(req: string): Promise<string>{

        req = `<req2>${req}</req2>`; // 把请求包一下
        console.log(req);

        let res = await super.sendRequest(req);

        res = `<res2>${res}</res2>`; // 把结果包一下
        console.log(res);

        return res;
    }
}

把两个HttpHandler连起来

let httpHandler = new FirstHttpHandler(new SecondHttpHandler(undefined));
console.log('start')
httpHandler.sendRequest('request').then(res=>console.log('finish'));

输出:

start

<req1>request</req1> // 发请求前先在FirstHttpHandler里处理request

<req2><req1>request</req1></req2> // 在SecondHttpHandler里再次处理request

response // 返回数据

<res2>response</res2> // SecondHttpHandler对返回数据的第一次处理

<res1><res2>response</res2></res1> // FirstHttpHandler对返回数据的第二次处理

finish

处理的顺序就是 1221,中间是真正取数据的,这就是管道处理最基本的代码,用到的就是职责链模式。

当然职责链的形成有很多方式,这里采用的是装饰手段,保存下一个的引用的方式来形成一个链表,还可以采用队列或栈方式保存所有handler,按顺序执行。

状态模式 State

特点:通过状态来改变对象的行为。

用处:当对象的行为取决于它的状态或者有很多if else之类的是由状态控制的时候可以考虑状态模式,如常见的状态机。

注意:状态是由谁来转换。

下面用TypeScript简单实现一下状态模式: 大家都玩过游戏,控制游戏的主角时鼠标左键可以是移动,遇到怪时点击左键是攻击,遇到NPC时是对话。 下面就以这点简单实现个状态模式:

角色和状态的接口,状态只需要处理当前状态需要做的事:

interface Role{
    name: string;

    click();
    changeState(state: State);
}

interface State{
    handle(role: Role);
}

角色的具体实现:

class Player implements Role{
    private state: State;
    constructor(public name: string){
    }

    click(){
        if(this.state){
            this.state.handle(this);
        }
    }

    changeState(state: State){
        this.state = state;
        console.log(`change to ${this.state.constructor.name}`);
    }
}

状态的具体实现,分为移动状态,攻击状态,对话状态:

class MoveState implements State{
    static readonly instance = new MoveState();

    handle(role: Role){
        console.log(`${role.name} is moving`);
    }
}

class AttackState implements State{
    static readonly instance = new AttackState();

    handle(role: Role){
        console.log(`${role.name} is attacking`);
    }
}

class TalkState implements State{
    static readonly instance = new TalkState();

    handle(role: Role){
        console.log(`${role.name} is talking`);
    }
}

使用:

let player = new Player('brook');

player.changeState(MoveState.instance);
player.click();

player.changeState(AttackState.instance);
player.click();

player.changeState(TalkState.instance);
player.click();

//输出:
change to MoveState
brook is moving

change to AttackState
brook is attacking

change to TalkState
brook is talking

这样随着状态的变化,点击左键做不同的事。 对于由谁来驱动状态变化可以根据实际情况来考虑,简单的话直接放角色里面就行,由角色自己决定自己的状态,复杂的话可以考虑用表来驱动状态机,通过表过实现状态的跳转。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android源码框架分析

Android窗口管理分析(4):Android View绘制内存的分配、传递、使用

前文Android匿名共享内存(Ashmem)原理分析了匿名共享内存,它最主要的作用就是View视图绘制,Android视图是按照一帧一帧显示到屏幕的,而每一帧...

1823
来自专栏linux驱动个人学习

Android图形显示之硬件抽象层Gralloc【转】

1545
来自专栏H2Cloud

linux epoll 开发指南-【ffrpc源码解析】

摘要 关于epoll的问题很早就像写文章讲讲自己的看法,但是由于ffrpc一直没有完工,所以也就拖下来了。Epoll主要在服务器编程中使用,本文主要探讨服务器程...

3625
来自专栏小巫技术博客

App性能优化浅谈

863
来自专栏安富莱嵌入式技术分享

【RL-TCPnet网络教程】第21章 RL-TCPnet之高效的事件触发框架

本章节为大家讲解高效的事件触发框架实现方法,BSD Socket编程和后面章节要讲解到的FTP、TFTP和HTTP等都非常适合使用这种方式。实际项目中也推荐大家...

714
来自专栏双十二技术哥

Android性能优化(六)之卡顿那些事

对普通用户而言,类如内存占用高、耗流量、耗电量等性能问题可能不会轻易发现,但是卡顿问题用户一定会立马直观的感受到。本文就带你一览卡顿的发生、检测、及优化。

602
来自专栏向治洪

Android Project Butter分析

一 背景知识介绍 随着时间的推移,Android OS系统一直在不断进化、壮大,日趋完善。但直到Android 4.0问世,有关UI显示不流畅的问题也一直未得到...

2049
来自专栏拭心的安卓进阶之路

Android 性能优化:多线程

前言 Android Performance Patterns Season 5 主要介绍了 Android 多线程环境下的性能问题。通过介绍 Android ...

1929
来自专栏吴小龙同學

Android之进程和线程

进程 线程 应用启动时,系统会为应用创建一个名为“主线程”的执行线程。 此线程非常重要,因为它负责将事件分派给相应的用户界面小工具,其中包括绘图事件。 此外,它...

3086
来自专栏向治洪

android开发性能分析

1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾。不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结、我一总结的都说到了很多优化注意事项...

2075

扫码关注云+社区