JHHK

欢迎来到我的个人网站
行者常至 为者常成

12、优化和重构技巧

目录

优化和重构技巧

通过前面两篇,MVC转MVP的介绍,我们总结一些优化和重构代码的技巧

一 事不过三

1.大段重复的代码出现了三次或以上

提取成一个公共的方法,这一点是最常见也最容易做到的,只要在平时的编码过程中养成这种习惯,对于出现过三次以上重复代码段,提取成一个公共方法。

2.一个类的职责有三种或以上

通过合理分层的方式,减少职责 这一点在MVP的例子中已经阐述地比较清楚了,通过职责的分层,上层持有下层,下层通过接口与上层通讯。其实这也是MVP模式的本质。

3.同类的if/else出现了三次或以上

考虑使用抽象类和多态代替if/else 如果相同的if/else判断在你的代码中出现了很多次的话,则应该考虑设计一个抽象类去替代这些判断。这里可能有点难以理解,举个例子就好懂很多 比如,现在我们有一个水果类,有三种水果,水果有颜色、价钱和品种

class Fruit {
    
    var name:String = ""
    
    func getColor() -> UIColor? {
        if name == "apple" {
            return UIColor.red
        } else if name == "banana" {
            return UIColor.yellow
        } else if name == "orange" {
            return UIColor.orange
        }
        return nil
    }

    func getPrice() -> Float? {
        if name == "apple" {
            return 10
        } else if name == "banana" {
            return 20
        } else if name == "orange" {
            return 30
        }
        return nil
    }
    
    func getType() -> String? {
        if name == "apple" {
            return "红富士"
        } else if name == "banana" {
            return "芭蕉"
        } else if name == "orange" {
            return "皇帝"
        }
        return nil
    }
}

这里的对名称name的相同的if/else判断出现了三次,如果此时我们多了一种水果梨,我们得修改上述所有的if/else判断,这样就会非常难维护。 这种场景我们可以考虑抽象出一个Fruit的抽象类/接口/协议,通过实现水果类/接口/协议的方式,此时如果多了一种水果,让这种水果继续实现Fruit协议就行,这样我们就通过新增的方式替代修改,提高了代码的可维护性。


protocol Fruit {
    func getPrice() -> Float?
    func getType() -> String?
    func getColor() -> UIColor?
    var name:String { get }
}

class Apple:Fruit {
    var name:String = "apple"
    func getColor() -> UIColor? {
        return UIColor.red
    }
    
    func getPrice() -> Float? {
        return 10
    }
    
    func getType() -> String? {
        return "红富士"
    }
}

class Banana:Fruit {
    var name:String = "banana"
    func getColor() -> UIColor? {
        return UIColor.yellow
    }
    
    func getPrice() -> Float? {
        return 20
    }
    
    func getType() -> String? {
        return "芭蕉"
    }
}

class Orange:Fruit {
    var name:String = "orange"
    func getColor() -> UIColor? {
        return UIColor.orange
    }
    
    func getPrice() -> Float? {
        return 30
    }
    
    func getType() -> String? {
        return "皇帝柑"
    }
}

二 合理分层

1.纵向分层——层级之间有关联

上层持有下层,下层通过接口与上层通信。这里为什么不让下层也持有上层呢?主要还是为了能够解耦,下层设计的目的是为上层服务的,它不应该依赖上层。这种设计模式在计算机科学中是很常见的,比如计算机网络中的网络分层设计。

2.横向分层——层级之间无关联

适用于功能相对独立的模块,简单划分即可。我们的iOS项目的首页就是由好几个部分组成,这个部分之间无太多的关联,我们简单划分成几个模块就行。如果出现了少数需要通讯的场景,使用Notification即可。

三 避免过度设计

1.越简单的越是有效的

复杂的架构设计往往在客户端高速迭代开发中意义不大(相比服务端)

2.没有银弹!

软件开发是工程化的,没有完美的架构模式,很多时候需要具体问题具体分析,灵活运用设计模式,得到局部的最优解。 比如前面提到的MVP模式,如果生搬硬套,同样无法解决Presenter层复杂的问题。

3.如何判断过度设计?

胶水代码过多,大量文件的行数小于100
想了一天,没写出代码,也没写出架构方案

四 重构的时机和对象

1.时机

单文件代码行数开始超过500行的时候
Code Review是重构的好帮手

2.对象

需求经常变化或增加的功能,一定要注意设计,避免走向质量不可控
稳定且不变的功能,不重构

总结

最后我想谈谈设计模式。其实重构的过程其实也就是灵活运用设计模式对代码进行优化和改进。很多人设计模式也看了很多,学习了很多,但真正在工作中能合理使用的却很少。所以关键还在灵活运用四个字上,能做到这一点,你的水平就会上一个台阶。

所以在平时的工作中,我们要有对代码的Taste,知道什么样的是好代码,什么样的是脏代码,尽早发现可优化可改进的地方,持续产出高质量代码,而不是实现功能就万事大吉,否则迟早要为你以前偷的懒买单。 以上就是我在项目重构过程中的一些总结和分享,水平有限,希望对大家有所帮助。


行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.