iOS 遵循开闭原则的实际案例讨论

2019-04-11  本文已影响0人  黑羽肃霜

案例:

假设现在有一个工具类,目的是把传入页面指定区域渲染成红色

不好的设计

定义一个基类 BaseFlushedViewController: UIViewController,返回一个 flushArea, 供工具类进行染色。

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

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

那么我们传入的参数必须是他的子类,而且由于每个页面可能需要刷新的视图是不同的,我们理论上应该重写他的 flushArea 方法

这样做的问题有两个:

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
    }
}

面相接口的设计

定义一个协议

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

这样做的好处:

比较

看起来面向接口的方法和使用基类的方法相比,只是工具类中的接口统一成了一个。但实际上,面向接口的方法中,SomeNavViewControllerSomeFlushedTabViewController 都是 UIViewController 的一种特例。而使用基类的实现方法中,三种 Base 类则是平级的基类,是为了覆盖所有的页面类型。

假设如果有一种新的导航页面,那么面向基类的方法,就还要去新增一个新的基类覆盖这个特例,面向接口的则只需要扩展出一个新的类型即可,工具类接口不需要新增。

以上的思想,就是面向对象设计规则中 开闭原则的一种体现。

上一篇下一篇

猜你喜欢

热点阅读