Свифт-протокол-ориентированные расширения
Попытка разобраться в протоколно-ориентированном программировании в Swift и о том, как работают расширения и какой уровень расширяемости он может обеспечить.
Получите следующий фрагмент кода, который я пробежал по игровым площадкам
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, я получу ошибку времени компиляции. Есть ли в любом случае, что я могу обойти это?
Благодарю.
1 ответ
Задача расширений состоит в том, чтобы обеспечить реализацию по умолчанию для методов протокола.
В вашем примере компилятор разрешит вызывать doSomethingA()
метод расширения, который лучше всего подходит для вашего конкретного объекта, но это все.
Как вы можете видеть в вашей точке вызова:
obj.doSomethingA()
Вы выполняете один вызов метода. Это будет решено и отправлено одному вызову метода, а не четырем.
Это похоже на то, что когда вы переопределяете метод через подклассы и вызываете метод базового класса, вызывается только производный метод, а не базовый класс. В этом случае, если вы хотите, вы можете позвонить super.method()
из подкласса.
В вашем случае, если вы хотите, чтобы вызывалось несколько методов, вы можете дать им отдельные имена и реализации через расширения, а затем просто создать класс, который реализует все протоколы следующим образом:
class A: ProtocolA, ProtocolB, ProtocolC {
func all() {
doSomethingA()
doSomethingB()
doSomethingC()
}
}
Преимущество расширений здесь в том, что ваш class A
не должен предоставлять реализации для трех методов.