扩展协议以实现不同的行为

问题描述 投票:4回答:5

快速的问题,比如说你有一个协议Bark:

protocol MakeSound {
   func bark()
}

超级狗,实现树皮和游泳:

class Dog: MakeSound {
}

然后不同类型的狗延伸:

class Poodle: Dog {
}

class GermanShephard: Dog {
}

class SheepDog: Dog {
}

但是poodles yap,他们不会吠叫......所有的狗都吠叫,他们只是采取不同的方式......我如何给他们特定的树皮行为?

扩展协议?...

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

然后贵宾犬和德国牧羊犬都有这两种行为(一个叫做德国牧羊犬?!)

如果我进行2次扩展并使用Self =检查类型类?

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

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

但我只能检查一种类型或狗类型。 SheepDogs也叫,但我不能在这里检查......

我知道在Java中,您可以扩展具有多个不同实现的接口。你如何使用协议在Swift中使用协议来解决这个问题呢?

swift protocols strategy-pattern swift-protocols
5个回答
3
投票

如果我理解你的问题,也许这很有帮助。

你可以通过扩展协议给bark()一个默认的实现。然后在符合协议的其他类上,您可以更改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

您也不能执行任何默认实现,只需为每种情况添加自己的实现

评论后编辑:

这是协议有用的主要原因之一。它们消除了与子类化有关的紧耦合。这是一个基本的例子,因为整个主题是很多信息,但不是子类化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分配给一个类时,它将获得基类将获得的所有默认实现,并且您被迫调用bark()函数以正确地符合协议:

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()
}

这样你就可以获得像基类一样的所有默认实现,但是不会忘记覆盖超类函数。

根据第二条评论编辑2:

在这种情况下,你最好的选择是离开DogRepresentable而不遵守Barkable,然后为不同类型创建协议:所以如果你有狗,你可以做一个具有树皮功能和默认实现的协议Yappable。然后你可以拥有另一个Barkable协议,它有自己的bark函数和它自己的默认实现。然后让类符合他们应该遵循的协议。 Poodle符合Yappable,Dog符合Barkable。

通过创建这些单独的协议,您可以将每种情况的功能保留在一个位置,并且只使用您需要的任何一个,从而使代码更清晰,更易读和干燥。


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
投票

这就是答案,makeSound协议是由2种不同的吠叫声协议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

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()

0
投票

只要父类没有标记为final,它的功能就可以被覆盖。 现在,当一个类符合协议时,您基本上通过添加变量/函数来满足协议的要求。

在你的情况下,由于Dog类没有被标记为final,你可以简单地覆盖bark函数。 没有什么特别要求,它毕竟只是一个功能

例:

protocol Barkable {
    func bark()
}

class Dog: Barkable {
    func bark() {
        print("Dog barks")
    }
}

class Poodle: Dog {
    override func bark() {
        print("Poodle yaps")
    }
}

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

class SheepDog: Dog {
    override func bark() {
        print("SheepDog barks")
    }
}

Dog().bark()
Poodle().bark()
GermanShephard().bark()
SheepDog().bark()
© www.soinside.com 2019 - 2024. All rights reserved.