Расширения, ориентированные на протокол Swift

Пытаюсь разобраться в протокольно-ориентированном программировании в Swift, понять, как работают расширения и какой уровень расширяемости он может обеспечить.

Имейте следующий фрагмент кода, который я пропустил через Playgrounds

protocol ProtocolA {
    func doSomethingA()
}

protocol ProtocolB {
    func doSomethingB()
}

protocol ProtocolC {
    func doSomethingC()
}

extension ProtocolA {
    func doSomethingA() {
        print("Extension - doSomethingA")
    }
}

extension ProtocolA where Self: ProtocolB {
    func doSomethingA() {
        print("Extension - doSomethingA Self: ProtocolB")
    }
}

extension ProtocolA where Self: ProtocolC {
    func doSomethingA() {
        print("Extension - doSomethingA Self: ProtocolC")
    }
}

extension ProtocolA where Self: ProtocolB, Self: ProtocolC {
    func doSomethingA() {
        print("Extension - doSomethingA Self: ProtocolB, ProtocolC")
    }
}

extension ProtocolB {
    func doSomethingB() {
        print("Extension - doSomethingB")
    }
}

extension ProtocolC {
    func doSomethingC() {
        print("Extension - doSomethingC")
    }
}

class Implementation: ProtocolA, ProtocolB, ProtocolC {
}

let obj = Implementation()

obj.doSomethingA()

То, что я печатаю, это:

Extension - doSomethingA Self: ProtocolB, ProtocolC

В любом случае, я могу гарантировать запуск всех расширений.

В идеале я хотел бы получить следующий результат.

Extension - doSomethingA
Extension - doSomethingA Self: ProtocolB
Extension - doSomethingA Self: ProtocolC
Extension - doSomethingA Self: ProtocolB, ProtocolC

Я понимаю, что Swift выберет наиболее сильное соответствие с точки зрения его типов, на самом деле, если я не предоставлю реализацию, в которой ProtocolA соответствует как ProtocolB, так и ProtocolC, я получу ошибку времени компиляции. Есть ли способ обойти это?

Спасибо.


person Peymankh    schedule 02.07.2016    source источник
comment
вы хотите, чтобы он делал все три ???   -  person Fattie    schedule 02.07.2016
comment
@JoeBlow Верно.   -  person Peymankh    schedule 02.07.2016
comment
Ты имеешь ввиду. Когда вы вводите это в код: obj.doSomethingA() вы на самом деле хотите, чтобы он выполнял четыре разных процедуры. Так, как бы вы назвали супер.... четыре раза, ну три раза, по наследственной цепочке????   -  person Fattie    schedule 02.07.2016
comment
@JoeBow Точно, это то, что я имею в виду. Проблема в том, что я хотел бы предоставить реализации по умолчанию на основе типов протоколов, а не реализовывать массивные супер-реализации, которые должны были бы учитывать каждый маленький случай, который могут использовать только несколько подклассов.   -  person Peymankh    schedule 02.07.2016
comment
Теперь я понимаю, что это может быть неизбежно.   -  person Peymankh    schedule 02.07.2016


Ответы (1)


Смысл расширений в том, чтобы обеспечить реализацию по умолчанию для методов протокола.

В вашем примере компилятор решит вызвать метод doSomethingA() расширения, который лучше всего подходит для вашего конкретного объекта, но это все.

Как вы можете видеть в вашей точке вызова:

obj.doSomethingA()

Вы выполняете один вызов метода. Это будет разрешено и отправлено в один вызов метода, а не в четыре.

Это похоже на то, когда вы переопределяете метод через подкласс и вызываете метод базового класса, вызывается только производный метод, а не метод базового класса. В этом случае, если вы хотите, вы можете вызвать super.method() из подкласса.

В вашем случае, если вы хотите вызвать несколько методов, вы можете дать им отдельные имена и реализации через расширения, а затем просто создать класс, который реализует все протоколы следующим образом:

class A: ProtocolA, ProtocolB, ProtocolC {

   func all() {
      doSomethingA()
      doSomethingB()
      doSomethingC()
   }
}

Преимущество расширений здесь в том, что ваш class A не должен предоставлять реализации для трех методов.

person bizz84    schedule 04.07.2016
comment
Справедливо. Спасибо. - person Peymankh; 04.07.2016