Share implementations with protocols

Viewed 58

I have two presenters: FirstPresenter and SecondPresenter. FirstPresenter conform to protocol PresenterProtocol. SecondPresenter needs to use all functions from FirstPresenter but with two additional.

protocol PresenterProtocol: class {
  func one()
  func two()
  func third()
}

class FirstPresenter: PresenterProtocol {

  func one() {

  // do something
 }

  func two() {

  // do something
 }

  func third() {

  // do something
 }
}

And then I have SecondPresenter and I need to use exactly the same implementation from FirstPresenter (but I want to avoid inheritance, I want do it with protocols)

class SecondPresenter: PresenterProtocols {

var firstPresenter: PresenterProtocol = FirstPresenter()

 func one() {
    firstPresenter.one()
  // do something
 }

  func two() {
    firstPresenter.two()
  // do something
 }

  func third() {
    firstPresenter.third()
  // do something
 }

 func additionalFunction() {
   // do something more
 }
}

I am not sure if calling firstpresenter function is a good way to solve this problem, because it's just rewriting. I wonder also to use default implementation. What's the best way to share functionalities?

2 Answers

Having a parent class is the better implementation as far as I see. But, if you don't want to, swift protocols have a nifty trick: the protocols can be extended.

Let me demonstrate using your code,

protocol PresenterProtocol: class {
  func one()
  func two()
  func third()
}

// Adding the extenstion/default implementation
extension PresenterProtocol {
  func one() {
    print("one was pressed")
  }

  func two() {
    print("two was pressed")
  }

  func third() {
    print("third was pressed")
  }
}

This way, any class conforming to PresenterProtocol will use the so-called "default implementation" (which is another way to say protocol extensions) unless you override the method in the class.

So your usage will look something like the following where you don't need to implement the 3 methods all over again.

class SecondPresenter: PresenterProtocol {
  // Calling default implementations
  func someFunction() {
    one() 
    two()
    third()
  }
}
.
.
.
class FirstPresenter: PresenterProtocol {
  func someFunction() {
    one()
    two()
    third()
  }
}

If you want more help learning, I would highly suggest reading the HackingWithSwift Tutorial

Your code doesn't actually rely on the methods you define, so they don't need to be requirements. They're extensions. As written, your code would be:

// This is where *requirements* go. Not shared code.
protocol PresenterProtocol: class {}

// This is your shared code
extension PresenterProtocol {
  func one() {

  // do something
 }

  func two() {

  // do something
 }

  func third() {

  // do something
 }
}

// And FirstPresenter needs nothing else
class FirstPresenter: PresenterProtocol {}

// SecondPresenter gets those, and also has other things
class SecondPresenter: PresenterProtocols {
 func additionalFunction() {
   // do something more
 }
}

Now, I'm betting that one() actually has some requirements. It needs its implementers to provide something. Those are what go in your PresenterProtocol. For example:

extension PresenterProtocol {
  func one() {
      doFirstThing()   // Something the implementer must do
      doSecondThing()  // Something the implementer must do
  }
}

In that case, you'd add those as requirements:

protocol PresenterProtocol {
    func doFirstThing()
    func doSecondThing()
}

And if there were a default way to do it that some implementers might override, then you'd provide a default implementation. Or you can just have all implementers provide it directly. Or you might not have any requirements at all.

Related