2016-12-15 11 views
4

Swift вопрос, скажем, например, у вас есть Bark протокола:Расширение протокола для реализации различного поведения

protocol MakeSound { 
    func bark() 
} 

супер класса собака, которая реализует кору, а также плавать:

class Dog: MakeSound { 
} 

Тогда разные виды собак, которые распространяются на это:

class Poodle: Dog { 
} 

class GermanShephard: Dog { 
} 

class SheepDog: Dog { 
} 

Но пудели яп, они не лают ... все собаки кора, они просто делают это по-другому ... Как я могу дать им определенное поведение Барка?

Направить протокол? ...

extension MakeSound { 
    func bark() 
    func yapper() 
} 

Но пудели и немецкие Shephards имеют оба поведения (тявкать немецкий Шепард ?!)

Если я делаю 2 расширения и проверить класс типа с использованием где Self =?

extension MakeSound where Self: GermanShephard { 
    func bark() { 
     print("Bark") 
    } 
} 

extension MakeSound where Self: Poodle{ 
    func yapper() { 
     print("yap yap") 
    } 
} 

Но я могу проверить только тип одного типа или тип собаки. SheepDogs также лают, но я не могу проверить здесь ...

Я знаю. На Java вы можете расширить интерфейс с несколькими различными реализациями. Как вы можете это сделать, используя протоколы в Swift, используя протоколы для решения этой проблемы?

+0

Что бы ваш подход для этого быть в Java? Это было бы точно так же, как в Свифте. – Alexander

ответ

3

Если я правильно понимаю ваш вопрос, возможно, это поможет.

Вы можете дать bark() реализацию по умолчанию, расширив протокол. Тогда на другие классы, которые соответствуют протоколу вы можете изменить реализацию функции коры:

protocol Bark { 
    func bark() 
} 

//default implementation 
extension Bark { 
     func bark() { print("Bark") } 
} 

class Dog: Bark {} 

//By calling bark func in Poodle, you change the default implementation. 
class Poodle: Dog { 
    func bark() { print("Yap") } 
} 

class GermanShephard: Dog { 
    func bark() { print("Woof") } 
} 

let dog = Dog() 
let poodle = Poodle() 
let germanShephard = GermanShephard() 

dog.bark() 
//Bark 
poodle.bark() 
//Yap 
germanShephard.bark() 
//Woof 

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

Edit после комментария:

Это одна из основных причин, по которой протоколы полезны. Они удаляют жесткую связь, связанную с подклассом. Это базовый пример, поскольку во всей теме много информации, но вместо подкласса Dog вы можете сделать протокол DogRepresentable и назначить все привилегии и функции по умолчанию, которые все собаки реализуют одинаково. Тогда вы можете расширить DogRepresentable где самостоятельно: UIViewController и реализовать функциональные возможности по умолчанию:

protocol Barkable { 
    func bark() 
} 

protocol DogRepresentable: Barkable { 
//properties and functions all dogs will have with same implementation 
} 

extension DogRepresentable where Self: UIViewController { 
//default implementation for functions all dogs will use 
} 

Назначая Barkable к DogRepresentable, вы знаете, любой класс, который соответствует DogRepresentable также должны соответствовать Barkable.

Теперь, когда вы назначаете DogRepresentable к классу, он получит всю реализацию по умолчанию базового класса будет получить, и вы вынуждены вызвать функцию коры(), чтобы соответствовать протоколу должным образом:

class Dog: DogRepresentable { 
    func bark() { print("Bark") } 
} 

class Poodle: DogRepresentable { 
    func bark() { print("Yap") } 
} 

class GermanShephard: DogRepresentable { 
    //Won't conform because it doesn't have bark() 
} 

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

Edit 2 на основе второго комментария:

В этом случае вам лучше всего оставить DogRepresentable, не соответствуя к Barkable, а затем создать протоколы для различных типов: так что если у вас есть собака, которые Яп вы могли бы сделать протокол Yappable который имеет функцию коры и реализацию по умолчанию. Затем вы можете использовать другой протокол Barkable со своей собственной функцией коры и собственную реализацию по умолчанию. Затем совместите класс с протоколом, которому они должны соответствовать. Пудель соответствует Yappable, Собака соответствует Barkable.

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

+0

Спасибо, я только что отредактировал вопрос выше, чтобы быть более понятным. Я думаю, что ваше решение может сработать ... Но что, если Пудель забыл переопределить, а затем он начинает лаять? Могу ли я защитить от этого? –

+1

Я имею в виду, например, если у меня есть много собак, которые едят. Я не хочу повторять код, переопределяя всю функцию коры. Я хочу использовать другую функцию протокола в MakeSound для yapping, но разрешите использовать только определенные типы собак. –

+0

Ваш отступ является ... художественным? – Alexander

0

Это ответ. Протокол makeSound реализуется двумя различными звуковыми сигналами протоколов dogYap и dogBark. Которые, в свою очередь, расширяют и реализуют различные звуки для лая и притирания. Затем классы различных типов собак (которые расширяют собаку) могут реализовать dogYap или dogBark, в зависимости от того, какой звук производит собака.

protocol MakeSound { 
    func makeSound() 
    var canBark: Bool { get } 
    var canYap: Bool { get } 
} 

protocol dogBark: MakeSound { 
    func makeSound() 
} 

protocol dogYap: MakeSound { 
    func makeSound() 
} 

extension dogYap { 
    func makeSound() { 
     print("Yap") 
    } 
} 

extension dogBark { 
    func makeSound() { 
     print("bark") 
    } 
} 

extension MakeSound { 
    func makeSound() {} 
    var canBark: Bool { return self is dogBark } 
    var canYap: Bool { return self is dogYap } 

} 

class Dog { 
    var age: Int? 
    var colour: UIColor? 

} 

class Poodle: Dog, dogYap { 
} 

class GermanShephard: Dog, dogBark { 
} 

class SheepDog: Dog, dogBark { 
} 

//German shephard and Belgian bark in the same way 
let germanShep = GermanShephard() 
germanShep.makeSound() 
germanShep.canBark 
germanShep.canYap 


let sheepDog = SheepDog() 
sheepDog.makeSound() 
sheepDog.canBark 
sheepDog.canYap 

let poodle = Poodle() 
poodle.makeSound() 
poodle.canBark 
poodle.canYap 
+1

Я бы обескуражил такой дизайн. Базовые типы не должны содержать информацию об их производных типах. Такой подход делает базовый тип не растяжимым. – Alexander

+0

Вы имеете в виду базовый тип Собака, имеющая возраст и цвет, является информацией об их базовых типах? В основном из вашего ответа выше (спасибо, кстати), и здесь я вижу, что вы вообще не использовали наследование. Где должен храниться возраст и цвет каждой собаки? –

+0

Нет, я говорю о том, как протокол 'MakeSound' знает и зависит от его производных протоколов,' dogBark' и 'dogYap'. Например, эта конструкция не позволяет мне расширять 'MakeSound' до' dogWoof'. – Alexander

2

Это идеальный прецедент для наследования протокола.

protocol DogSoundMaker { 
    func makeSound() 
} 

protocol Barker: DogSoundMaker {} 
protocol Yapper: DogSoundMaker {} 
protocol Woofer: DogSoundMaker {} 

extension Barker { 
    func makeSound() { print("Bark") } 
} 

extension Yapper { 
    func makeSound() { print("Yap yap, I am a glorified rodent") } 
} 

extension Woofer { 
    func makeSound() { print("Woof") } 
} 

struct Poodle: Yapper {} 
struct GermanShephard: Barker {} 
struct SheepDog: Woofer {} 

Poodle().makeSound() 
GermanShephard().makeSound() 
SheepDog().makeSound() 
0

Я считаю, что это правильный способ реализации такого рода поведения:

import UIKit 

protocol DogSoundMaker {} 
protocol Barker: DogSoundMaker {} 
protocol Yapper: DogSoundMaker {} 

extension DogSoundMaker{ 
    var canBark: Bool { return self is Barker } 
} 
extension Barker { 
    func makeSound() { 
     print("Bark") 
    } 
} 
extension Yapper { 
    func makeSound() { 
     print("Yap") 
    } 
} 

class GermanShepherd: Barker { 

} 

class Poodle: Yapper{ 

} 

class Chiwawa: Yapper { 

} 

var germanShep = GermanShepherd() 
var poodleDog = Poodle() 
poodleDog.makeSound() 
poodleDog.canBark 
germanShep.canBark 
germanShep.makeSound() 

 Смежные вопросы

  • Нет связанных вопросов^_^