看看用TypeScript怎样实现常见的设计模式,顺便复习一下。

学模式最重要的不是记UML,而是知道什么模式可以解决什么样的问题,在做项目时碰到问题可以想到用哪个模式可以解决,UML忘了可以查,思想记住就好。

这里尽量用原创的,实际中能碰到的例子来说明模式的特点和用处。

中介者模式 Mediator

特点:为减少对象间的互相引用而引入的一个中介对象,用来来封装一系列对象的互相操作。

用处:当多个对象间需要互相引用且互相频繁操作时可以考虑中介者模式,如MVC里的Controller。

注意:中介者本身的复杂度。

下面用TypeScript简单实现一下中介模式:

现在滴滴打车其实就可以算是中介,就以这个例子吧,对象主要就是用户,车主和平台。

先定义用户, 车主和中介者接口:

用户的行为是叫车,车主是接送,中介者则需要维护用户和车主列表并且知道车的状态和提供叫车服务。

interface Client{
getTaxi();
pay();
} interface Car{
isWorking: boolean; startWork();
finishWork();
} interface Mediator{ registerClient(client: Client);
registerCar(car: Car); getCar(): Car;
pay(car: Car);
updateCarStatus(car: Car);
}

接口定义好了就可以写实现了:

用户的实现,持有中介者的引用,用来注册,叫车和付款,本来是没必要存taxi的,只需要个id就可以了,具体是由中介去做匹配,不过这里为了简单就直接存对象了

class User implements Client{
taxi: Car; constructor(private mediator: Mediator){
this.mediator.registerClient(this);
} getTaxi(){
this.taxi = this.mediator.getCar();
if(this.taxi){
console.log('车来了');
} else {
console.log('没叫到车');
}
} pay(){
this.mediator.pay(this.taxi);
console.log('付款');
}
}

车主的实现,同样需要持有中介者引用来领任务和报状态

class Taxi implements Car{
isWorking: boolean = false; constructor(private mediator: Mediator){
this.mediator.registerCar(this);
} startWork(){
console.log('有人叫车');
this.isWorking = true;
this.mediator.updateCarStatus(this);
} finishWork(){
console.log('送完这趟了');
this.isWorking = false;
this.mediator.updateCarStatus(this);
}
}

中介的实现,中介的作用就是提供车子服务,这里为了简单没维护用户与车子的关系

class DiDi implements Mediator{
private clientList: Array<Client> = [];
private carList: Array<Car> = []; registerClient(client: Client){
this.clientList.push(client);
} registerCar(car: Car){
this.carList.push(car);
} getCar(): Car{
let car = this.carList.find(o=>!o.isWorking);
car.startWork();
return car;
} pay(car: Car){
car.finishWork();
} updateCarStatus(car: Car){
console.log(`车子状态:${car.isWorking ? '工作' : '闲置'}`);
}
}

跑一下看看:

let didi = new DiDi();
let taxi = new Taxi(didi);
let user = new User(didi);
user.getTaxi();
user.pay(); //结果
有人叫车
车子状态:工作
车来了
送完这趟了
车子状态:闲置
付款

这样,用户的目的只是叫车,对中介说声,中介派出车,用户不管是什么车,哪来的,把我送到目的地就可以了。

这就是中介者模式的作用,逻辑都在自己这里,用户不需要管车,车子也不用管用户,一个叫车,一个接单,互不干扰,突然想到了拉皮条。。。

当然也是因为这里聚集了各方面的逻辑,所以要注意中介者本身的复杂度,中介者本身也需要良好的设计和模式来提高代码的可读性和可维护性。

观察者模式 Observer

特点:定义了对象间的一对多关系,当对象状态改变时,其他订阅了这个对象的对象就会收到通知。

用处:当一个对象状态的改变时需要其他对象也做出响应时可以考虑观察者模式,如网络聊天里的群。

注意:与中介者的区别。

下面用TypeScript简单实现一下观察者模式:

就以上面说的群聊天为例,群里的每个人都是注册到群里的对象,任何一个人发了信息其他人都能收到。

先定义群和群用户的接口:

群需要知道有哪些用户注册进来了,并且在有人发消息时去通知所有注册的人。

用户则需要发送消息和接收消息。

interface Observer{
name: string; sendMsg(msg: string);
receiveMsg(sender: Observer, msg: string);
} interface Subject{
register(observer: Observer);
unregister(observer: Observer);
sendMsg(sender: Observer, msg: string);
}

实现用户和群,用户在发消息时需要往群里发,群收到消息后通知所有注册的人

class User implements Observer{
constructor(public name: string, private subject: Subject){
this.subject.register(this);
} sendMsg(msg: string){
console.log(`${this.name} 发送 ${msg}`);
this.subject.sendMsg(this, msg);
} receiveMsg(sender: Observer, msg: string){
console.log(`${this.name} 收到来自${sender.name}的消息: ${msg} `);
}
} class Group implements Subject{
private userList: Array<Observer> = []; register(observer: Observer){
this.userList.push(observer);
} unregister(observer: Observer){
var index = this.userList.indexOf(observer);
if (index > -1) {
this.userList.splice(index, 1);
}
} sendMsg(sender: Observer, msg: string){
console.log(`群收到${sender.name}发信息:${msg},通知所有人`);
this.notify(sender, msg);
} private notify(sender: Observer, msg: string){
this.userList.forEach(user=>user.receiveMsg(sender, msg));
}
}

写段代码测试一下:

let group = new Group();
let jim = new User1('jim', group);
let brook = new User1('brook', group);
let lucy = new User1('lucy', group); jim.sendMsg('hello');
lucy.sendMsg('well done!');
//结果:
jim 发送 hello
群收到jim发信息:hello,通知所有人
jim 收到来自jim的消息: hello
brook 收到来自jim的消息: hello
lucy 收到来自jim的消息: hello lucy 发送 well done!
群收到lucy发信息:well done!,通知所有人
jim 收到来自lucy的消息: well done!
brook 收到来自lucy的消息: well done!
lucy 收到来自lucy的消息: well done!

只有要人发消息,所有注册的人都会收到,跟广播一样。

其实观察者模式可以做得更通用,类似一个消息中心,所有注册的对象按照一定协议实现匹配事件的方法来获取通知,消息中心不需要知道是什么类型的对象注册了,只要实现这个方法,那相关事件有通知时这个方法就会被调到,这样基本没有耦合度,有兴趣的朋友可以参考我之前写的一个win10开源库:LLQNotify,就是用这种方式实现的。

另外,与中介者模式的区别在于:虽然都是注册回复,但观察者是分发性的,注册的人都能收到,而且中介者则是单一的,使用者发个请求,中介者回一个,使用者不需要知道到底是谁回的,中介隐藏了对象之间的交互。

TypeScript设计模式之中介者、观察者的更多相关文章

  1. 乐在其中设计模式(C#) - 中介者模式(Mediator Pattern)

    原文:乐在其中设计模式(C#) - 中介者模式(Mediator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 中介者模式(Mediator Pattern) 作者:weba ...

  2. 折腾Java设计模式之中介者模式

    博文原址:折腾Java设计模式之中介者模式 中介者模式 中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性.这种模式提供了一个中介类,该类通常处理不同类之间的通信,并 ...

  3. js设计模式——8.中介者模式

    js设计模式——8.中介者模式 /*js设计模式——中介者模式*/ class A { constructor() { this.number = 0; } setNumber(num, m) { t ...

  4. 【TS】358- 浅析 TypeScript 设计模式

    点击上方"前端自习课"关注,学习起来~ 作者:DD菜 https://zhuanlan.zhihu.com/p/43283016 设计模式就是软件开发过程中形成的套路,就如同你在玩 ...

  5. [译]Java 设计模式之中介者

    (文章翻译自Java Design Pattern: Mediator) 中介者设计模式被用于一组的同事进行协作.这些同事不彼此进行直接的交流联系,但是是通过中介者. 在下面的例子中,A同事想去说话, ...

  6. 设计模式的征途—15.观察者(Observer)模式

    在日常生活中,交通信号灯指挥者日益拥挤的城市交通.红灯亮,汽车停止:绿灯亮,汽车继续前行:在这个过程中,交通信号灯是汽车的观察目标,而汽车则是观察者.随着交通信号灯的变化,汽车的行为也会随之变化,一盏 ...

  7. 深入理解JavaScript系列(36):设计模式之中介者模式

    介绍 中介者模式(Mediator),用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 主要内容来自:http://www ...

  8. 【GOF23设计模式】中介者模式

    来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_中介者模式.同事协作类.内部类实现 package com.test.mediator; /** * 同事类的接口 */ ...

  9. [设计模式] 17 中介者模式 Mediator Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对中介者模式是这样说的:用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变 ...

随机推荐

  1. abstract、override、new、virtual、sealed使用和示例

    abstract修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽象类,则这个类智能是其他某个类的基类.抽象方法在抽象类中没有函数体.抽象类中的抽象方法是没有方法体的,继承其的子类必须实现抽象类的抽 ...

  2. SQLSERVER如何导入数据保持ID不变(ID为自增主键)

    使用SQL SERVER最操蛋的就是导入数据,以前用企业管理器直接导数据,导一次骂N次娘,在骂了微软无数次娘之后总结了一个方法揍合着还算受用. 其核心要点就是要将数据结构导入到目标数据库服务器上,再来 ...

  3. 2017qq红包雨最强攻略,

    这个只支持苹果手机,而且要有苹果电脑,只有苹果手机是不行的. QQ红包规则:只要你到达指定的位置,就可以领取附近的红包,一般也就几毛,还有几分的,当然也不排除有更高的,只不过我是没遇到... 那么既然 ...

  4. Go并发编程实践

    前言 并发编程一直是Golang区别与其他语言的很大优势,也是实际工作场景中经常遇到的.近日笔者在组内分享了我们常见的并发场景,及代码示例,以期望大家能在遇到相同场景下,能快速的想到解决方案,或者是拿 ...

  5. Yii2 独立操作

    看到最近有些人在问 yii2 独立操作相关的东西,在这做简单的说明吧, 平时核心业务逻辑一般用的还是比较少的.因为  独立操作 出现的原因 是 对重复被使用的操作进行简化,或 分配一个 额外处理逻辑的 ...

  6. 关于WIN10开机无法输入密码的问题

    昨日,电脑 遇到了开机无法输入密码的问题,神烦. 作为一个计算狗,怎么能直接装系统(百度了一堆方法,装系统,果真万能)呢. 所以,深刻的分析了下. 1 .首先说明基本情况. 计算机品牌:ASUS 系统 ...

  7. ActionMode 就记这么一点,不能更多了

    话说程序猿都是段子手,看到有的程序猿写文章,前面都会先写一个段子,我这么有幽默感的段子手,也决定效仿一下. "段子." 写完段子,下面开始进入正题. 今天要说的 ActionMod ...

  8. Java变量&&简单程序流程&&循环

    变量:强类型局部变量: 1.先赋值,后使用 2.作用范围:从定义开始,到所在代码块结束 3.重合范围内不允许重复命名 数据类型(8中基本类型) byte 1B -128~127 short 2B -3 ...

  9. [Hadoop] - Hadoop Mapreduce Error: GC overhead limit exceeded

    在运行mapreduce的时候,出现Error: GC overhead limit exceeded,查看log日志,发现异常信息为 2015-12-11 11:48:44,716 FATAL [m ...

  10. css中书写小三角

    我们在开发过程中,有很多的方向标签不是图片,而是用css方法书写上去的. 首先我们要了解原理,border的边框的脚步是45度角. 向左方向: width:0px: height:0px: borde ...