iOS 遵循開閉原則的實際案例討論

案例:

假設如今有一個工具類,目的是把傳入頁面指定區域渲染成紅色swift

很差的設計

定義一個基類 BaseFlushedViewController: UIViewController,返回一個 flushArea, 供工具類進行染色。工具

class FlushHelper {
    static func flush(_ viewController: BaseFlushedViewController) {
        viewController.flushArea().backgroundColor = .red
    }
}

class BaseFlushedViewController: UIViewController {
    func flushArea() -> UIView {
        return view
    }
}
複製代碼

那麼咱們傳入的參數必須是他的子類,並且因爲每一個頁面可能須要刷新的視圖是不一樣的,咱們理論上應該重寫他的 flushArea 方法spa

這樣作的問題有兩個:設計

  • 新建的頁面類可能會忘記重寫該方法
  • 若是須要傳入的頁面是一個 UINavigatiionControllerUITabbarController呢?(有可能我如今要渲染導航欄或底部標籤欄),那麼我還要再在工具類中新增兩個接口適應。這顯然不是咱們想要的
class FlushHelper {
    static func flush(_ viewController: BaseFlushedViewController) {
        viewController.flushArea().backgroundColor = .red
    }
    
    static func flush(_ viewController: BaseFlushedNavViewController) {
        viewController.flushArea().backgroundColor = .red
    }
    
    static func flush(_ viewController: BaseFlushedTabViewController) {
        viewController.flushArea().backgroundColor = .red
    }
}

class BaseFlushedViewController: UIViewController {
    func flushArea() -> UIView {
        return view
    }
}

class BaseFlushedNavViewController: UINavigationController {
    func flushArea() -> UIView {
        return view
    }
}

class BaseFlushedTabViewController: UITabBarController {
    func flushArea() -> UIView {
        return tabBar
    }
}
複製代碼

面相接口的設計

定義一個協議code

protocol Flushable {
    func flushArea() -> UIView
}

class FlushHelper {
    static func flush(_ viewController: UIViewController & Flushable) {
        viewController.flushArea().backgroundColor = .red
    }
}

class SomeViewController: UIViewController, Flushable {
    func flushArea() -> UIView {
        return view
    }
}

class SomeNavViewController: UINavigationController, Flushable {
    func flushArea() -> UIView {
        return navigationBar
    }
}

class SomeFlushedTabViewController: UITabBarController, Flushable {
    func flushArea() -> UIView {
        return tabBar
    }
}
複製代碼

將工具類的接口統一成 UIViewController & Flushable對象

這樣作的好處:繼承

  • 調用工具類接口時,十分明確的知道傳入的頁面要去實現 flushArea 方法,不存上文提到的在繼承以後忘記重寫的狀況
  • 適配全部的 UIViewController 及其子類。不須要工具類再開放額外的接口

比較

看起來面向接口的方法和使用基類的方法相比,只是工具類中的接口統一成了一個。但實際上,面向接口的方法中,SomeNavViewControllerSomeFlushedTabViewController 都是 UIViewController 的一種特例。而使用基類的實現方法中,三種 Base 類則是平級的基類,是爲了覆蓋全部的頁面類型。接口

假設若是有一種新的導航頁面,那麼面向基類的方法,就還要去新增一個新的基類覆蓋這個特例,面向接口的則只須要擴展出一個新的類型便可,工具類接口不須要新增。it

以上的思想,就是面向對象設計規則中 開閉原則的一種體現(如有錯誤歡迎指正)。io

相關文章
相關標籤/搜索