I have been trying to grasp protocol-oriented-programming but i don't understand the difference between the 2 following scenarios...
Scenario 1
I have two classes that are UIViewControllers
. Both of these classes need to use some common functionality so I create a protocol and an extension with a default implementation of the protocol and then the view controllers only need have the protocol in the class line and they will automatically inherit the needed functionality. ie...
protocol SomeProtocol {
func foo()
}
extension SomeProtocol {
func foo(){
//execute
}
}
class FirstViewController: UIViewController, SomeProtocol {
...
func doSomething(){
foo()
}
}
class SecondViewController: UIViewController, SomeProtocol {
...
func doSomethingElse(){
foo()
}
}
Scenario 2
I have two classes that are UIViewControllers
. Both of these classes need to use some common functionality so I create a controller class and both UIViewController
classes use an instance of the controller class. ie...
class FirstViewController: UIViewController {
...
let controller = Controller()
func doSomething(){
controller.foo()
}
}
class SecondViewController: UIViewController {
...
let controller = Controller()
func doSomethingElse(){
controller.foo()
}
}
class Controller {
func foo(){
//execute...
}
}`
So what is the difference? Anywhere that I need to use the foo()
function I could just grab an instance of Controller()
. What advantage do I get by putting the foo()
function in a protocol and then having the classes that need foo()
inherit from the protocol?
There are a couple of approaches when you want to add this
foo
functionality to multipleUIViewController
(or what have you) subclasses:The protocol approach with extensions:
The problem is that while this works great with Swift-only code, it doesn't work so well when you're writing code that must be called by Cocoa directly.
The merit of this approach (when you can) is that you start to enjoy the advantages outlined in WWDC 2015 Protocol-Oriented Programming in Swift.
The component approach (where you have some
Controller
instance that your view controllers can vend):This is great when you need shared functionality that will be integrating directly with Cocoa. For example, this can be used when doing custom view controller transitions and don't want to repeat code in the various view controllers. This approach can be a manifestation of the single responsibility principle and can help fight view controller bloat.
For the sake of completeness, there are a few more options to achieve reuse:
As matt suggested, you can also implement
foo
as an extension to some shared base class.This works great when the routine makes sense for not just your two existing subclasses, but all subclasses. But this is not appropriate if this is functionality unique to just those two particular subclasses.
You can also put
foo
into a subclass of that base class (e.g.FooViewController
subclassesUIViewController
), and then have your two previous subclasses then subclass that newFooViewController
class.This addresses the indiscriminate nature of a simple extension of the base class.
The problem is that this is not as flexible as the first two approaches (e.g. no multiple inheritance, one set of
Fooable
methods and another set ofBarable
methods).Bottom line, the right approach depends up the specific problem you're trying to solve. Your example is too generic for us to offer specific counsel.