博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
TypeScript设计模式之策略、模板方法
阅读量:4928 次
发布时间:2019-06-11

本文共 3331 字,大约阅读时间需要 11 分钟。

看看用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
{ 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
{ protected handleResponse(): ClassA{ console.log('handle response for Server A'); return null; }}class RequesterForServerB extends RequesterBase
{ protected handleResponse(): ClassB{ console.log('handle response for Server B'); return null; }}let requesterA: RequesterBase
= new RequesterForServerA('server A');let requesterB: RequesterBase
= new RequesterForServerB('server B');requesterA.reqeustData();requesterB.reqeustData();//输出send request, url: server Ahandle response for Server Asend request, url: server Bhandle response for Server B

这里可以看到主体功能由基类RequesterBase实现,两个子类则实现解析数据这些细节,这样就达到了消除重复代码的目的。

如果还有个ServerC的request发送部分也不一样,也没关系,TypeScript天生虚函数,在子类直接实现reqeustData即可,多态的作用下,运行时还是会调用到子类上。

转载于:https://www.cnblogs.com/brookshi/p/6505643.html

你可能感兴趣的文章
谜题32:循环者的诅咒
查看>>
RMI
查看>>
动态切换多数据源的配置
查看>>
win7电脑调整分区后分区不见的文件寻回法子
查看>>
《第一行代码》学习笔记2-Android开发特色
查看>>
bzoj3396 [Usaco2009 Jan]Total flow 水流
查看>>
20165231 2017-2018-2 《Java程序设计》第3周学习总结
查看>>
(180905)如何通过梯度下降法降低损失----Google机器学习速成课程笔记
查看>>
(响应式PC端媒体查询)电脑屏幕分辨率尺寸大全
查看>>
LDAP1-安装部署LDAP服务
查看>>
Crystal Reports拉报表报错:Error detected by database DLL
查看>>
border-radius讲解1
查看>>
CLR via C#学习笔记-第九章-参数和返回类型的设计规范
查看>>
dom4j解析XML文件(3)—XML文件写入
查看>>
vi作者:Bill Joy
查看>>
0139-文件操作之二进制方式打开模式(一).abb
查看>>
自定义分享功能
查看>>
基于Attribute的Web API路由设置
查看>>
vue使用中的随笔
查看>>
use sql trigger call java function
查看>>