TypeScript设计模式之策略、模板方法

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

策略模式 Strategy

特点:用组合的方式调用一些算法或逻辑,并且可以根据状态不同而选用不同的算法或逻辑。

用处:对象需要运行时切换算法或逻辑可以考虑使用策略模式。

注意:策略的生成方式。

下面用TypeScript简单实现一个策略模式: 说起策略就想到策略类游戏,年龄大点的可能都玩过War3,人族对兽族时如果侦察到对方不着急升本,用常规万金油打法,那人族就可以出狗男女来一波流。 如果侦察到兽族跳科技并摆下两个兽栏,那对方可能是暴飞龙,人族就要家里补个塔防偷农民,然后出点火枪或二本龙鹰。

class Orc{
    private _shenKeJi = false;

    get shenKeJi(): boolean { // 这里简单用升科技来判断是用常规还是飞龙
        return this._shenKeJi;
    }

    set shenKeJi(value: boolean){
        this._shenKeJi = value;
    }
}

abstract class Stragety{
    abstract execute();
}

class RushStragety extends Stragety{
    execute(){
        console.log('升科技');
        console.log('出狗男女');
        console.log('一波流');
    }
}

class DefendStragety extends Stragety{
    execute(){
        console.log('补塔防飞龙');
        console.log('出火枪');
        console.log('升科技');
        console.log('出龙鹰');
    }
}

class Human{
    stragety: Stragety;

    checkOrc(orc: Orc){
        if(orc.shenKeJi){ //根据兽族情况来决定策略
            console.log('侦察到兽族是跳科技打法');
            this.stragety = new DefendStragety();
        } else {
            console.log('侦察到兽族是常规打法');
            this.stragety = new RushStragety();
        }
    }

    deal(){
        this.stragety && this.stragety.execute();
    }
}

let orc = new Orc();
let human = new Human();

orc.shenKeJi = false;
human.checkOrc(orc);
human.deal();

orc.shenKeJi = true;
human.checkOrc(orc);
human.deal();

//输出
侦察到兽族是常规打法
升科技
出狗男女
一波流

侦察到兽族是跳科技打法
补塔防飞龙
出火枪
升科技
出龙鹰

这样人族就可以根据兽族的状态改变来做出不同的应对策略,其实现在游戏的AI基本都是通过决策树来实现的,也算是策略模式,只是更复杂,通过各种不同的条件最终得到一个决策来做出反应。

另外,有人可能已经发现了,上面生成策略的地方是可以拿出来,用之前讲的工厂模式来做,因为实际应用时策略通常比较多,甚至可能同时需要多种相关策略,用工厂模式来生产策略就可以很好的隐藏细节,解除依赖。

模板方法模式 Template Method

特点:通过多态来实现在运行时使用不同的算法或逻辑,通常有一个整体架子,通过抽象方法或虚方法来把细节代码延迟到子类实现。

用处:当多个类似功能的类有很多相同结构或代码时,可以抽象出整体架子时可以考虑模板方法。

注意:与策略模式的异同:同样是细节部分交出去,不同在于策略是对象行为,采用的是组合的方式,而模板方法是类行为,采用的是继承。

下面用TypeScript简单实现一个模板方法模式: 比方说发送http请求的代码,需要向两台不同的server(A和B)发送请求,两台server除了url不同,回来的数据格式也不一样,但由于都是http请求,主体架子是一样的,所以可以用模板方法来实现下。

class ClassA{} // Server A 返回的数据结构
class ClassB{} // Server B 返回的数据结构

abstract class RequesterBase<T>{

    constructor(private url: string){

    }

    reqeustData(): T{
        this.sendReqeust();
        return this.handleResponse();
    }

    protected sendReqeust(){
        console.log(`send request, url: ${this.url}`);
    }

    protected abstract handleResponse(): T; // 不同的server返回的数据交由子类去实现
}

class RequesterForServerA extends RequesterBase<ClassA>{
    protected handleResponse(): ClassA{
        console.log('handle response for Server A');
        return null;
    }
}

class RequesterForServerB extends RequesterBase<ClassB>{
    protected handleResponse(): ClassB{
        console.log('handle response for Server B');
        return null;
    }
}

let requesterA: RequesterBase<ClassA> = new RequesterForServerA('server A');
let requesterB: RequesterBase<ClassB> = new RequesterForServerB('server B');

requesterA.reqeustData();
requesterB.reqeustData();

//输出
send request, url: server A
handle response for Server A

send request, url: server B
handle response for Server B

这里可以看到主体功能由基类RequesterBase实现,两个子类则实现解析数据这些细节,这样就达到了消除重复代码的目的。 如果还有个ServerC的request发送部分也不一样,也没关系,TypeScript天生虚函数,在子类直接实现reqeustData即可,多态的作用下,运行时还是会调用到子类上。

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏枕边书

小时到分钟 - 一步步优化巨量关键词的匹配

问题由来 前些天工作中遇到一个问题: 有 60万 条短消息记录日志,每条约 50 字,5万 关键词,长度 2-8 字,绝大部分为中文。要求将这 60万 条记录中...

1706
来自专栏大数据

No.67 Hadoop 实践案例——记录去重

转载声明 本文为灯塔大数据原创内容,欢迎个人转载至朋友圈,其他机构转载请在文章开头标注:转自:灯塔大数据;微信:DTbigdata 编者按:灯塔大数据将每周持续...

1788
来自专栏java一日一条

有经验的Java开发者和架构师容易犯的10个错误(上)

首先允许我们问一个严肃的问题?为什么Java初学者能够方便的从网上找到相对应的开发建议呢?每当我去网上搜索想要的建议的时候,我总是能发现一 大堆是关于基本入门的...

512
来自专栏一个会写诗的程序员的博客

第1章 Kotlin是什么第1章 Kotlin是什么

当下互联网大数据云计算时代,数以百万计的应用程序在服务器、移动手机端上运行,其中的开发语言有很大一部分是用流行软件界20多年的、强大稳定的主力的编程语言Java...

732
来自专栏带你撸出一手好代码

使用测试用例来约束自己的代码

写测试代码这种事情 ,以前只在网上和书上看到过, 自己从来没有写过。 每当看到那些世界顶级程序员编写的技术书籍中出现“测试用例”“测试代码”的字样或者一些行业的...

3226
来自专栏逸鹏说道

.Net中的AOP读书笔记系列之AOP介绍

AOP是什么? Hello,World! 小结 本系列的源码本人已托管于Coding上:点击查看,想要注册Coding的可以点击该连接注册。 本系列的实验环境:...

34511
来自专栏前端架构

CPU阿甘:函数调用的秘密

上帝为你关闭了一扇门,就一定会为你打开一扇窗这句话来形容我最合适不过了。 我是CPU, 他们都叫我阿甘, 因为我和《阿甘正传》里的阿甘一样,  有点傻里傻气的。...

772
来自专栏HansBug's Lab

【作业】HansBug的前三次OO作业分析与小结

OO课程目前已经进行了三次的作业,容我在本文中做一点微小的工作。 第一次作业 第一次作业由于难度不大,所以笔者程序实际上写的也比较随意一些。(点击就送指导书~)...

3046
来自专栏Python中文社区

基于Redis的Bloomfilter去重

专栏作者简介 九茶 Python工程师,目前居于广州。Github知名开源爬虫QQSpider和SinaSpider作者,经常会在CSDN上分享一些爬虫、数据等...

4518
来自专栏java一日一条

我的编码习惯 - Controller规范

第一篇文章中,我贴了2段代码,第一个是原生态的,第2段是我指定了接口定义规范,使用AOP技术之后最终交付的代码,从15行到1行,自己感受一下。今天来说说大家关注...

501

扫码关注云+社区