关于“幽灵架构”的总结:适用场景与方法重载

来源:互联网 发布:淘宝中老年夏季女装 编辑:程序博客网 时间:2024/04/28 21:36

前几篇博文对“幽灵架构”做了用法的介绍和相关技术点的补充,本文是一篇总结性质的文章,分析该架构的适用场景和限制,首先让我们回顾一下iOS开发的MVC模式,参考斯坦福公开课里Paul老爷子的讲解,如下图所示:
这里写图片描述
在MVC模式下Model和View是不能直接通信的,在“幽灵架构”体系中Model和View依旧不能直接通信,在传统的MVC中,这种通信的阻隔很多时候是因为在没有得到Model和View实体的情况下无法完成二者的数据绑定,在过去你可能想过在View中写一个方法来接受一个模型,然后写具体的实现,在没有泛型的帮助下只能用方法的重载来做,没有协议扩展的情况下需要在父类和写重复的代码中做选择。
在“幽灵架构”体系中,通过ModelType和ViewType可以在不借助控制器的帮助下实现二者的逻辑绑定,依旧是使用了方法传值的用法,Controller起到了“开关”的作用,依靠泛型和协议对数据类型进行了约束,并且避免了重复代码,不需要在意数据源的同构和异构。
我们需要在Controller中创建Model和View的实例,并且和MVC一样可以对Model和View做处理,但是Model和View之间的逻辑关系是定义在View的getData中的,比如Demo中Event的Cell会被标注为红色,如果要通过修改Controller的标志位来影响Model和View之间的逻辑,比如Demo中在Controller中加入一个开关,点击后会互换Event和Festival的背景色,这就属于Controller中引入了标志位来影响View和Model的逻辑,此时如果要继续维持“幽灵架构”的体系,那么需要重载giveData和getData方法,传入Controller中的标志位。首先给getData增加默认实现,因为在View的代码中我们只想重写需要的重载的方法:

//视图使用的协议protocol ViewType{    func getData<M:ModelType>(model:M)}//数据使用的协议protocol ModelType{}//定义默认方法giveDataextension ModelType{    func giveData<V:ViewType>(view:V){        view.getData(self)    }}extension ViewType{    func getData<M:ModelType>(model:M){    }}

为了维持“幽灵架构”的灵活性,我们重写了giveData和getData,不是在具体的遵守者中重写,而是直接扩展协议:

extension ModelType where Self:HasDate{    func giveData<V:ViewType>(view:V,tag:Bool){        if let tableCell = view as? ShowedTableViewCell{            tableCell.getData(self,tag:tag)        }    }}extension ViewType where Self:ShowedTableViewCell{    func getData<M : ModelType>(model: M,tag:Bool){    }}

现在不需要修改所有的Model,但是需要在View中重写新定义的方法:

func getData<M : ModelType>(model: M,tag:Bool) {        //这里不能写成guard let dateModel = model as? DateViewModel else{}令我有些意外        guard let dateModel = model as? HasDate else{            return        }        //处理相同属性        dateLabel.text = dateModel.date        //处理数据源异构        if let event = dateModel as? Event{            MixLabel.text = event.eventTitle            backgroundColor = tag  ? UIColor.redColor():UIColor.whiteColor()        } else if let festival = dateModel as? Festival{            MixLabel.text = festival.festivalName            backgroundColor = !tag  ? UIColor.redColor():UIColor.whiteColor()        }    }

这是协议扩展的另一个神奇之处:不会引入多余的状态,避免了“上帝类”的出现,如果你的工程中有其他的Model和View的绑定,不会受到任何影响。最后一步,修改Controller中的数据绑定:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {        let cell = tableView.dequeueReusableCellWithIdentifier(cellReusedID, forIndexPath: indexPath) as! ShowedTableViewCell        //调用重载的方法        dataList[indexPath.row].giveData(cell,tag:true)        return cell    }

现在尝试向tag传入true和false看看效果吧:
这里写图片描述
tag传入false
这里写图片描述
tag的值取决于Controller,从上面的例子中看出在Controller中切换View和Model的绑定逻辑是完全没问题的。之前讲过giveData方法是为了在异构数据源中避免Box类型的出现,提高运行效率,针对同构的数据源,我们只需要重载getData并在控制器中直接使用getData对数据进行捆绑就好了。
所以,我之所以在最初的文章中称“幽灵架构”为MV,其实并没有弱化控制器的职责,但是把控制器中有关于模型和视图逻辑绑定的代码移到了View中,并且集中在了getData一个方法中,便于维护,为控制器减压,所以其实这是一个“伪架构”。从上面的示例中可以看到,MVC和MVVM能做到的“幽灵架构”一样能做到,并且比MVC中控制器的代码更好维护,比MVVM少写了很多代码。“幽灵架构”今后的发展,需要经历时间的考验了。

1 0