Combining class inheritance with protocol inheritance

So far, we have created many protocols for our animals. Some of these protocols inherit from other protocols; therefore, we have a protocol hierarchy tree. Now, it is time to combine class inheritance with protocol inheritance to recreate our animal classes.

The following lines show the new version of the Animal class that conforms to the AnimalProtocol protocol. The code file for the sample is included in the swift_3_oop_chapter_05_12 folder:

    open class Animal: AnimalProtocol { 
      open class var numberOfLegs: Int { 
        get { 
          return 0; 
        } 
      } 
      open class var averageNumberOfChildren: Int { 
        get { 
          return 0; 
        } 
      } 
     
      open class var abilityToFly: Bool { 
        get { 
          return false; 
        } 
      } 
     
      open var age: Int 
     
      init(age : Int) { 
        self.age = age 
        print("Animal created") 
      } 
     
      open class func printALeg() { 
        preconditionFailure("The pringALeg method must be overriden") 
      } 
     
      open func printLegs() { 
        for _ in 0..<type(of: self).numberOfLegs { 
          type(of: self).printALeg() 
        } 
        print(String()) 
      } 
     
      open class func printAChild() { 
        preconditionFailure("The printChild method must be overriden") 
      } 
     
      public func printChildren() { 
        for _ in 0..<type(of: self).averageNumberOfChildren { 
          type(of: self).printAChild() 
        } 
        print(String()) 
      } 
     
      public func printAge() { 
        print("I am (age) years old.") 
      } 
    } 

The following lines show the new version of the Mammal class that inherits from the Animal class and conforms to the MammalProtocol protocol. The code file for the sample is included in the swift_3_oop_chapter_05_12 folder:

    open class Mammal: Animal, MammalProtocol { 
      open var isPregnant: Bool = false 
     
      private func initialize(isPregnant: Bool) { 
        self.isPregnant = isPregnant 
        print("Mammal created") 
      } 
     
      override init(age: Int) { 
        super.init(age: age) 
        initialize(isPregnant: false) 
      } 
     
      init(age: Int, isPregnant: Bool) { 
        super.init(age: age) 
        initialize(isPregnant: isPregnant) 
      } 
    } 

The following lines show the new version of the DomesticMammal class that inherits from the Mammal class and conforms to the DomesticProtocol protocol. Remember that the DomesticProtocol protocol doesn't inherit from any other protocol. The code file for the sample is included in the swift_3_oop_chapter_05_12 folder:

    open class DomesticMammal: Mammal, DomesticProtocol { 
      open var name = String() 
      open var favoriteToy = String() 
     
      private func initialize(name: String, favoriteToy: String) { 
        self.name = name 
        self.favoriteToy = favoriteToy 
        print("DomesticMammal created") 
      } 
     
      init(age: Int, name: String, favoriteToy: String) { 
        super.init(age: age) 
        initialize(name: name, favoriteToy: favoriteToy) 
      } 
     
      init(age: Int, isPregnant: Bool, name: String, 
      favoriteToy: String) { 
        super.init(age: age, isPregnant: isPregnant) 
        initialize(name: name, favoriteToy: favoriteToy) 
      } 
     
      public func talk() { 
        print("(name): talks") 
      } 
    } 

The following lines show the new version of the Dog class that inherits from the DomesticMammal class and conforms to the DogProtocol protocol. The code file for the sample is included in the swift_3_oop_chapter_05_12 folder:

    open class Dog: DomesticMammal, DogProtocol { 
      open static override var numberOfLegs: Int { 
        get { 
          return 4; 
        } 
      } 
     
      open static override var abilityToFly: Bool { 
        get { 
          return false; 
        } 
      } 
     
      open var breed: String { 
        get { 
          return "Just a dog" 
        } 
      } 
     
      open var breedFamily: String { 
        get { 
          return "Dog" 
        } 
      } 
     
      private func initializeDog() { 
        print("Dog created") 
      } 
     
      override init(age: Int, name: String, favoriteToy: String) { 
        super.init(age: age, name: name, favoriteToy: favoriteToy) 
        initializeDog() 
      } 
     
      override init(age: Int, isPregnant: Bool, name: String, 
      favoriteToy: String) { 
        super.init(age: age, isPregnant: isPregnant, name: name, 
        favoriteToy: favoriteToy) 
        initializeDog() 
      } 
     
      public final func printBreed() { 
        print(breed) 
      } 
     
      public final func printBreedFamily() { 
        print(breedFamily) 
      } 
     
      open func printBark(times: Int, otherDomestic: DomesticProtocol?, 
      isAngry: Bool) { 
        var bark = "(name)" 
        if let unwrappedOtherDomestic = otherDomestic { 
          bark += " to (unwrappedOtherDomestic.name): " 
        } else { 
          bark += ": " 
        } 
        if isAngry { 
          bark += "Grr " 
        } 
        for _ in 0 ..< times { 
          bark += "Woof " 
        } 
        print(bark) 
      } 
     
      open func bark() { 
        printBark(times: 1, otherDomestic: nil, isAngry: false) 
      } 
     
      open func bark(times: Int) { 
        printBark(times: times, otherDomestic: nil, isAngry: false) 
      } 
     
      open func bark(times: Int, otherDomestic: DomesticProtocol) { 
        printBark(times: times, otherDomestic: otherDomestic, 
        isAngry: false) 
      } 
     
      open func bark(times: Int, otherDomestic: DomesticProtocol, 
      isAngry: Bool) { 
        printBark(times: times, otherDomestic: otherDomestic, 
        isAngry: isAngry) 
      } 
     
      open override func talk() { 
        bark() 
      } 
    } 

The previous version overloaded bark methods, which required an otherDomesticMammal argument of the DomesticMammal type. The printBark method required an optional otherDomesticMammal argument of the DomesticMammal? type. The new version of the overloaded bark methods replaces the otherDomesticMammal argument with otherDomestic of the DomesticProtocol type. This way, it is possible to pass any class that implements the DomesticProtocol protocol. The new version of the printBark method requires an optional otherDomestic argument of the DomesticProtocol type. These changes allow dogs to bark at any other domestic animal, just like the domestic bird we will create later. The previous version was only capable of barking at other domestic mammals. However, in real-life scenarios, dogs do bark at birds.

It is not necessary to make any changes to the classes that inherit from Dog: TerrierDog and SmoothFoxTerrier. These classes remain with the same code that we introduced in Chapter 4, Inheritance, Abstraction, and Specialization.

The following lines show the new version of the Cat class that inherits from the DomesticMammal class and conforms to the CatProtocol protocol. The code file for the sample is included in the swift_3_oop_chapter_05_12 folder:

    open class Cat: DomesticMammal, CatProtocol { 
      open static override var numberOfLegs: Int { 
        get { 
          return 4; 
        } 
      } 
     
      open static override var abilityToFly: Bool { 
        get { 
          return false; 
        } 
      } 
     
      open override class var averageNumberOfChildren: Int { 
        get { 
          return 6; 
        } 
      } 
     
      private func initializeCat() { 
        print("Cat created") 
      } 
     
      override init(age: Int, name: String, favoriteToy: String) { 
        super.init(age: age, name: name, favoriteToy: favoriteToy) 
        initializeCat() 
      } 
     
      override init(age: Int, isPregnant: Bool, name: String, 
      favoriteToy: String) { 
        super.init(age: age, isPregnant: isPregnant, name: name, 
        favoriteToy: favoriteToy) 
        initializeCat() 
      } 
     
      open func printMeow(times: Int) { 
        var meow = "(name): " 
        for _ in 0 ..< times { 
          meow += "Meow " 
        } 
        print(meow) 
      } 
     
      open override func talk() { 
        printMeow(times: 1) 
      } 
     
      open override class func printALeg() { 
        print("*_*", terminator: String()) 
      } 
     
      open override class func printAChild() { 
        // Print grinning cat face with smiling eyes emoji 
        print(String(UnicodeScalar(0x01F638)!), terminator: String()) 
      } 
    } 

The following lines show the new version of the Bird class, which inherits from the Animal class and conforms to the BirdProtocol protocol. The code file for the sample is included in the swift_3_oop_chapter_05_12 folder:

    open class Bird: Animal, BirdProtocol { 
      open var feathersColor: String = String() 
     
      open static override var numberOfLegs: Int { 
        get { 
          return 2; 
        } 
      } 
     
      private func initializeBird(feathersColor: String) { 
        self.feathersColor = feathersColor 
        print("Bird created") 
      } 
     
      override init(age: Int) { 
        super.init(age: age) 
        initializeBird(feathersColor: "Undefined / Too many colors") 
      } 
     
      init(age: Int, feathersColor: String) { 
        super.init(age: age) 
        initializeBird(feathersColor: feathersColor) 
      } 
    } 

The following lines show the new version of the DomesticBird class, which inherits from the Bird class and conforms to the DomesticProtocol protocol. Remember that the DomesticProtocol protocol doesn't inherit from any other protocol. The code file for the sample is included in the swift_3_oop_chapter_05_12 folder:

    open class DomesticBird: Bird, DomesticProtocol { 
      open var name = String() 
      open var favoriteToy = String() 
     
      private func initializeDomesticBird(name: String, 
      favoriteToy: String) { 
        self.name = name 
        self.favoriteToy = favoriteToy 
        print("DomesticBird created") 
      } 
     
      open func talk() { 
        print("(name): Tweet Tweet") 
      } 
     
      init(age: Int, name: String, favoriteToy: String) { 
        super.init(age: age) 
        initializeDomesticBird(name: name, favoriteToy: favoriteToy) 
      } 
     
      init(age: Int, feathersColor: String, name: String, 
      favoriteToy: String) { 
        super.init(age: age, feathersColor: feathersColor) 
        initializeDomesticBird(name: name, favoriteToy: favoriteToy) 
      } 
    } 

The new DomesticBird class adds the favoriteToy stored property and the talk method to conform to the DomesticProtocol protocol. In addition, the initializers add new parameters to make it possible to assign an initial value to favoriteToy.

The following lines show the new version of the DomesticCanary class, which inherits from the DomesticBird class. The code file for the sample is included in the swift_3_oop_chapter_05_12 folder:

    open class DomesticCanary: DomesticBird { 
      open override class var averageNumberOfChildren: Int { 
        get { 
          return 5; 
        } 
      } 
     
      private func initializeDomesticCanary() { 
        print("DomesticCanary created") 
      } 
     
      override init(age: Int, name: String, favoriteToy: String) { 
        super.init(age: age, name: name, favoriteToy: favoriteToy) 
        initializeDomesticCanary() 
      } 
     
      override init(age: Int, feathersColor: String, name: String, 
      favoriteToy: String) { 
        super.init(age: age, feathersColor: feathersColor, name: name, 
        favoriteToy: favoriteToy) 
        initializeDomesticCanary() 
      } 
       
      open override class func printALeg() { 
        print("^", terminator: String()) 
      } 
     
      open override class func printAChild() { 
        // Print bird emoji 
        print(String(UnicodeScalar(0x01F426)!), terminator: String()) 
      } 
    } 

The DomesticCanary class changes the initializers to match the edits made in its superclass: DomesticBird.

The following table summarizes the list of protocols to which each of the new versions of the classes we created conforms:

Class name

Conforms to the following protocol(s)

Animal

AnimalProtocol

Mammal

AnimalProtocol and MammalProtocol

DomesticMammal

AnimalProtocol, MammalProtocol, and DomesticProtocol

Dog

AnimalProtocol, MammalProtocol, DomesticProtocol, and DogProtocol

TerrierDog

AnimalProtocol, MammalProtocol, DomesticProtocol, and DogProtocol

SmoothFoxTerrier

AnimalProtocol, MammalProtocol, DomesticProtocol, and DogProtocol

Cat

AnimalProtocol, MammalProtocol, DomesticProtocol, and CatProtocol

Bird

AnimalProtocol and BirdProtocol

DomesticBird

AnimalProtocol, BirdProtocol, and DomesticProtocol

DomesticCanary

AnimalProtocol, BirdProtocol, DomesticProtocol

The following simplified UML diagram shows the hierarchy tree for the protocols and classes and their relationship:

Combining class inheritance with protocol inheritance

The following lines create an instance of Dog named pluto, an instance of Cat named marie, and an instance of DomesticCanary named tweety. Then, the next lines call the talk method for the three instances and make pluto bark at tweety. It is possible to use tweety as the otherDomestic argument for the bark method because it is an instance of DomesticCanary, and it conforms to the DomesticProtocol protocol. The code file for the sample is included in the swift_3_oop_chapter_05_12 folder:

    var pluto = Dog(age: 7, name: "Pluto", favoriteToy: "Teddy bear") 
    var marie = Cat(age: 4, isPregnant: true, name: "Marie", 
    favoriteToy: "Tennis ball") 
    var tweety = DomesticCanary(age: 2, feathersColor: "Yellow", 
    name: "Tweety", favoriteToy: "Small bell") 
 
    tweety.talk() 
    pluto.bark(times: 3, otherDomestic: tweety) 
    marie.talk() 
    pluto.talk() 

The following lines show the output generated by the last four lines of code:

    Tweety: Tweet Tweet 
    Pluto to Tweety: Woof Woof Woof  
    Marie: Meow  
    Pluto: Woof  

If we execute the following lines in the Playground, all of them will display true as a result because tweety is an instance of a class that conforms to three protocols: AnimalProtocol, BirdProtocol, and DomesticProtocol. In addition, tweety belongs to Animal, Bird, DomesticBird, and DomesticCanary:

print(tweety is AnimalProtocol) 
print(tweety is BirdProtocol) 
print(tweety is DomesticProtocol) 
print(tweety is Animal) 
print(tweety is Bird) 
print(tweety is DomesticBird) 
print(tweety is DomesticCanary) 

The following screenshot shows the results of executing the previous lines in the Playground. Note that the Playground uses an icon to let us know that all the is tests will always be evaluated to true:

Combining class inheritance with protocol inheritance

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.96.232