Home > database >  Refactoring OOP to Protocol Oriented Programming
Refactoring OOP to Protocol Oriented Programming

Time:09-16

I have FirstViewController which has some IBOutlets, functions and presenter. Then I have SecondViewController which has all same functions as FirstViewController but with one additional function, IBOutlets and presenter exactly same as presenter of FirstViewController, but with 1 additonal functions.

I have read about OOP and POP and people recommend to use POP.

But my question is if in this situation when I need to have SecondViewController with all same functions and IBOutlets as in FirstViewController, inheritance is not better than protocols?

If I want to use protocol, how should it to be done if I want to avoid rewrite same code? With protocols default implementation?

With inheritance

class FirstViewController: UIViewController {

 @IBOutlet weak var firstButton: UIButton!
 @IBOutlet weak var secondButton: UIButton!

...
...
 func firstFunction() {
  ...
 }

 func secondFunction() {
  ...
 }
}



class SecondViewController: FirstViewController {
    
     @IBOutlet weak var additionalButton: UIButton!
     
    ...
    ...
     func additionalFunction() {
      ...
     }
    }

With default implementation

protocol FirstViewControllerProtocols {
 func firstFunction()
 func secondFunction()
}

extension FirstViewControllerProtocols {

 func firstFunction() {
   print("do something")
 }

 func secondFunction() {
   print("do something")
 }
}

and then

 class FirstViewController: UIViewController, FirstViewControllerProtocols {

   @IBOutlet weak var firstButton: UIButton!
   @IBOutlet weak var secondButton: UIButton!
 }



protocol SecondViewControllerProtocol {
 func thirdFunction()
}

extension SecondViewControllerProtocol {
 func thirdFunction() {
   print("do something new")
 }
}

 class SecondViewController: UIViewController, FirstViewControllerProtocols, SecondViewControllerProtocol {
  
  @IBOutlet weak var additionalButton: UIButton!
 
 }
 

But with protocol approach I can't inherit iboutlets.

CodePudding user response:

Your example of POP is not correct. The point is just to extract the shared code into protocols, not duplicate things unnecessarily. So FirstViewControllerProtocols makes sense, but there's absolutely no reason for SecondViewControllerProtocol. What second type conforms to SecondViewControllerProtocol? If you get rid of that, you'll see that most of your problems go away.

But not all of them. You're also talking about IBOutlets, which are not just a matter of shared code. If SecondViewController really is a kind of FirstViewController (rather than just "happens to share a few buttons"), then inheritance might make sense. If it's just that there are a few related IBOutlets, duplicate the IBOutlets since they're related to the type. That's not inheritance.

Given your description, you're thinking in terms of "I have a lot of code that happens to be kind of similar, and so I should make a thing to abstract it." That's not the approach; if they're just "kind of similar" then ask yourself if you're creating abstractions for no purpose. If FirstViewController were changed, would SecondViewController necessarily also change? If not, they're not actually very related. "DRY" (Do not Repeat Yourself) is about concepts, not keystrokes.

The approach is "I have two things that are fundamentally similar, will change in similar ways over time, and have algorithms that should apply to both, so I should extract a protocol."

CodePudding user response:

Subclassing one view controller class from another custom view controller (as well as using default implementations in protocols) seems so elegant at first glance, but nine times out of ten, it is a mistake. If it is an abstract “base view controller”, for some common behavior, that can sometimes bear some utility (though depending upon what this shared behavior is, there are often better patterns).

But if these two view controller classes are used for different scenes in your storyboard (and your reference to sharing IBOutlets suggests that this is the case), it becomes, in my experience, a maintenance nightmare. I used this pattern in a few early projects, was quite pleased with the elegance of my code at the time, but when I was later modifying and enhancing the respective view controllers, I regretted having two view controller classes for two different scenes so tightly entangled.

Nowadays, we strive for view controller classes that are as thin and dumb as possible. (See Dave DeLong’s A Better MVC posts or the video. It is also one of the many motivating factors behind MVVM and related patterns.) View controllers are solely intended for configuring views and initiating behaviors upon user interaction or other system events. Anything beyond that should generally be abstracted out of the view controller. And if there are common UI elements in various view controllers, we will often consider view controller containment to abstract the shared UI to a third view controller which becomes a child of the first two.

So rather than POP vs OOP, ask yourself whether all this shared behavior belongs in either one of these two view controllers at all. If the shared behaviors are various UIKit delegate methods (e.g. table data source, collection view delegate methods, etc.), that calls for one solution. If they are business logic, it calls for a different solution. If they are utility methods, yet another. If it is a common set of subviews, again, yet another pattern. It just depends.

  • Related