Case study:
Suppose you now have a utility class that renders the specified area of the incoming page red
Bad design
Defines a base class BaseFlushedViewController: UIViewController, returns a flushArea, for tools for dyeing.
class FlushHelper {
static func flush(_ viewController: BaseFlushedViewController) {
viewController.flushArea().backgroundColor = .red
}
}
class BaseFlushedViewController: UIViewController {
func flushArea(a) -> UIView {
return view
}
}
Copy the code
The arguments we pass in must be subclasses of it, and since each page may need to refresh different views, we should theoretically rewrite its flushArea method
The problem with this is twofold:
- A new page class might forget to override this method
- If the required incoming page is one
UINavigatiionController
或UITabbarController
? (Maybe I’ll now render the navigation bar or the bottom TAB bar), then I’ll add two more interface adaptations to the tool class. That’s obviously not what we want
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(a) -> UIView {
return view
}
}
class BaseFlushedNavViewController: UINavigationController {
func flushArea(a) -> UIView {
return view
}
}
class BaseFlushedTabViewController: UITabBarController {
func flushArea(a) -> UIView {
return tabBar
}
}
Copy the code
Design of face interface
Define a protocol
protocol Flushable {
func flushArea(a) -> UIView
}
class FlushHelper {
static func flush(_ viewController: UIViewController & Flushable) {
viewController.flushArea().backgroundColor = .red
}
}
class SomeViewController: UIViewController.Flushable {
func flushArea(a) -> UIView {
return view
}
}
class SomeNavViewController: UINavigationController.Flushable {
func flushArea(a) -> UIView {
return navigationBar
}
}
class SomeFlushedTabViewController: UITabBarController.Flushable {
func flushArea(a) -> UIView {
return tabBar
}
}
Copy the code
Unify the interface of the utility class into UIViewController & Flushable
The benefits of this:
- When you call the utility class interface, you know exactly what the incoming page is to implement
flushArea
Method, do not forget to rewrite the case mentioned above after inheritance - Fit all
UIViewController
And subclasses. There is no need for utility classes to open additional interfaces
To compare
It looks like an interface oriented approach is just one interface in a utility class compared to one that uses a base class. But in fact, an interface method, SomeNavViewController and SomeFlushedTabViewController are a special case of the UIViewController. In the Base class implementation, the three Base classes are flat Base classes that cover all page types.
Suppose that if there is a new navigation page, then the base-oriented method needs to add a new base class to cover this special case, whereas the interface-oriented method only needs to extend a new type, and the utility class interface does not need to be added.
The above idea is an embodiment of the open and closed principle in object-oriented design rules (if there are mistakes welcome to correct).