phpmv设计_聊聊GUI开发中的MV*设计模式(二)

上一篇讲了MVC-Model-1和MVP模式,并且简单实践了一下MVC模式,这一篇我们继续实践MVP模式。

前情提要

我们要做的就是这样一个简单的应用,下拉菜单可以选择歌手,选择之后下方列表可以显示歌手对应的专辑。

MVP模式相较于MVC,有2点明显的好处:对View层做了接口抽象,后期测试可以直接mock view

移除了View对Model层的依赖,提高代码可复用性

IView

对View层的抽象,明确了View层的输入和输出:

export interface IPresenterView {

selectedEvent: UIEvent;

bindRecords(data: Array): void;

bindAuthors(data: Array): void;

}

对上面的程序来说,输入就是下拉列表的数据和列表项的数据,输出就是下拉列表选中之后的触发事件。

Model

model层和MVC一样也比较简单,并且移除了Observable的特性,通过Repository模式,暴露几个接口:

export class RecordsRepos {

private static data: Array;

getRecords(): Array {

return RecordsRepos.data;

}

getRecordsByAuthorName(name: string): Array {

return RecordsRepos.data.filter(r => r.name === name);

}

}

export class AuthorsRepos {

private static data: Array;

getAuthors(): Array {

return AuthorsRepos.data;

}

}

Presenter

讲道理这里应该是讲View层实现了,但是我们既然已经有了IView的接口,Model也有了,就可以正常开发Presenter了。这样才可以把MVP的优点发挥出来。

export class RecordsPresenter {

recordsRepo: RecordsRepos;

authorRepo: AuthorsRepos;

view: IPresenterView;

constructor(view: IPresenterView) {

this.view = view;

this.view.bindAuthors(this.authorRepo.getAuthors());

this.view.bindRecords(this.recordsRepo.getRecords());

this.view.selectedEvent.on(this.onAuthorSelected);

}

onAuthorSelected(arg: SelectEventArg) {

let records = this.recordsRepo.getRecordsByAuthorName(arg.name);

this.view.bindRecords(records);

}

}

我们在构造函数中调用IView的2个方法手动绑定了初始数据,并且监听了View的下拉选择事件。在事件处理程序里,我们从Model获取了新的数据,并且重新绑定了专辑列表数据。

当然,上面有些写的不太对(所以上一篇才要郑重声明),比如没对2个Model实例化,并且Model也应该抽象出接口来,后期通过依赖注入,进一步提高可测试性。

View

最后就是我们的View层了,照着IView接口来实现就好了。

export class PresenterView implements IPresenterView {

selectedEvent: UIEvent;

dropdownList: IDropdownList;

list: IList;

constructor() {

this.dropdownList.selectedEvent.on(this.onAuthorSelected);

}

bindRecords(data: T[]): void {

this.list.data = data;

}

bindAuthors(data: T[]): void {

this.dropdownList.data = data;

}

onAuthorSelected(arg: SelectEventArg) {

this.selectedEvent.emit(arg);

}

}

一个简单的应用实践下来,我们其实也能发现MVP模式的一些弊端。

首先,就是一些重复性的代码太多,特别是更新View的操作。这就导致了Presenter有点重。

所以我们可以 拆分一部分简单的UI逻辑到View层,这就是MVP的一个分支,Supervising Controller。而我们上面实现的,是MVP的一个基本分支,Passive View。对于这两种模式有兴趣的同学可以自己再深入了解。

结尾再聊聊MVVM,最早(不一定准确)应该是由我软在2005年提出的,随着WPF和SilverLight被发扬光大(其实死的很早)。相比较于MVP,Presenter被换成了ViewModel。

从View层考虑,ViewModel其实就是View的一个抽象,包含了他所需的数据和行为。 从Model层来看,ViewModel又像是一个值转换器,将Model转换成View层需要的一种格式,所以有时候MVVM又被称为Model-View-Binder模式。

借助于Data-Binding技术,MVVM完成了Model和View的双向绑定,也不再包含对View层的依赖,让开发者可以更专注于和状态和行为的管理。

在我软技术栈上,Data-Binding主要由XACML来实现,而前端的主流框架,例如React,Vue则是借助于单向数据流+V-DOM diff实现类似效果的。

优点省去Presenter中Model和View之间的手动同步,移除了对View的依赖

代码更简洁,可读性更强

缺点在大型项目上MVVM的性能可能会有问题

最后借用 韦恩叔的一句话来总结一下:M-V- X 本质都是一样的 重点还是在于M-V 的桥梁要靠 X来牵线。

X的模式之间不同 主要是 M与V 的数据传递的流程不同。

数据传递的流程不同来源于运行环境技术栈能够做到的事情不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值