Reader small image

You're reading from  Object???Oriented Programming with Swift 2

Product typeBook
Published inJan 2016
Reading LevelIntermediate
Publisher
ISBN-139781785885693
Edition1st Edition
Languages
Tools
Right arrow
Author (1)
Gaston C. Hillar
Gaston C. Hillar
author image
Gaston C. Hillar

Gaston C. Hillar is Italian and has been working with computers since he was 8 years old. Gaston has a Bachelor's degree in computer science (graduated with honors) and an MBA. Currently, Gaston is an independent IT consultant and a freelance author who is always looking for new adventures anywhere in the world. He was a senior contributing editor at Dr. Dobb's, and has written more than a hundred articles on software development topics. He has received the prestigious Intel Black Belt Software Developer award eight times. He has written many articles about Java for Oracle Java Magazine. Gaston was also a former Microsoft MVP in technical computing. He lives with his wife, Vanesa, and his two sons, Kevin and Brandon.
Read more about Gaston C. Hillar

Right arrow

Chapter 5. Contract Programming with Protocols

In this chapter, we will work with more complex scenarios in which we will have to use instances that belong to more than one blueprint. We use contract programming by taking advantage of protocols.

We will work with examples on how to define protocols, their different kinds of requirements, and then to declare classes that adopt the protocols. We will use the multiple inheritance of protocols and many useful ways of taking advantage of this object-oriented concept, also known as interfaces in other programming languages, such as Java and C#.

Understanding how protocols work in combination with classes


We have to work with two different types of characters: comic and game characters. A comic character has a nickname and must be able to draw speech balloons and thought balloons. The speech balloon might have another comic character as a destination.

A game character has a full name and must be able to perform the following tasks:

  • Draw itself in a specific 2D position indicated by the x and y coordinates

  • Move itself to a specific 2D position indicated by the x and y coordinates

  • Check whether it intersects with another game character

We will work with objects that can be both a comic character and a game character. However, we will also work with objects that will just be either a comic or game character. Neither the game nor the comic character has a generic way of performing the previously described tasks. Thus, each object that declares itself as a comic character must define the tasks related to speech and thought balloons. Each...

Declaring protocols


Now, it is time to code the protocols in Swift. We will code the following five protocols:

  • ComicCharacter

  • GameCharacter

  • Alien

  • Wizard

  • Knight

The following UML diagram shows the five protocols that we will code in Swift with their required properties and methods included in the diagram:

The following lines show the code for the ComicCharacter protocol. The public modifier followed by the protocol keyword and the protocol name, ComicCharacter, composes the protocol declaration. As it happens with class declarations, the protocol body is enclosed in curly brackets ({}):

public protocol ComicCharacter {
    var nickName: String { get set }

    func drawSpeechBalloon(message: String)
    func drawSpeechBalloon(destination: ComicCharacter, message: String)
    func drawThoughtBalloon(message: String)
}

The protocols declare a nickName read/write String stored property requirement, a drawSpeechBaloon method requirement overloaded twice, and a drawThoughtBalloon method requirement...

Declaring classes that adopt protocols


Now, we will declare a class that specifies that it conforms to the ComicCharacter protocol in its declaration in the Playground. Instead of specifying a superclass, the class declaration includes the name of the previously declared ComicCharacter protocol after the class name (AngryDog) and the colon (:). We can read the class declaration as "the AngryDog class conforms to the ComicCharacter protocol."

However, the class doesn't implement any of the required properties and methods specified in the protocol, so it doesn't really conform to the ComicCharacter protocol, as shown in the following:

public class AngryDog: ComicCharacter {

}

The Playground execution will fail because the AngryDog class doesn't conform to the ComicCharacter protocol, so the Swift compiler generates the following errors and notes:

error: type 'AngryDog' does not conform to protocol 'ComicCharacter'
public class AngryDog: ComicCharacter {
             ^
note: protocol requires...

Taking advantage of the multiple inheritance of protocols


Swift doesn't allow us to declare a class with multiple base classes or superclasses, so there is no support for multiple inheritance of classes. A subclass can inherit just from one class. However, a class can conform to one or more protocols. In addition, we can declare classes that inherit from a superclass and conform to one or more protocols. Thus, we can combine class-based inheritance with protocols.

We want the AngryCat class to conform to both the ComicCharacter and GameCharacter protocols. Thus, we want to use any AngryCat instance as both a comic character and a game character. In order to do so, we must change the class declaration and add the GameCharacter protocol to the list of protocols that the class conforms to and declare all the members included in this added protocol within the class.

The following lines show the new class declaration that specifies that the AngryCat class conforms to both, the ComicCharacter and...

Combining inheritance and protocols


We can combine class inheritance with protocol conformance. The following lines show the code for a new AngryCatAlien class that inherits from the AngryCat class and conforms to the Alien protocol. Note that the class declaration includes the superclass (AngryCat) and the implemented protocol (Alien) separated by a comma after the colon (:):

public class AngryCatAlien : AngryCat, Alien {
    public var numberOfEyes: Int = 0
    
    init (nickName: String, age: UInt, fullName: String, initialScore: UInt, x: UInt, y: UInt, numberOfEyes: Int) {
        super.init(nickName: nickName, age: age, fullName: fullName, initialScore: initialScore, x: x, y: y)
        self.numberOfEyes = numberOfEyes
    }
    
    public func appear() {
        print("I'm \(fullName) and you can see my \(numberOfEyes) eyes.")
    }
    
    public func disappear() {
        print("\(fullName) disappears.")
    }
}

As a result of the previous code, we have a new class named AngryCatAlien...

Working with methods that receive protocols as arguments


Now, we will create additional instances of the previous classes and call methods that specified their required arguments with protocol names instead of class names. We will understand what happens under the hood when we use protocols as types.

In the following code, the first two lines of code create two instances of the AngryDog class named brian and merlin. Then, the code calls the two versions of the drawSpeechBalloon method for brian. The second call to this method passes merlin as the ComicCharacter argument because merlin is an instance of AngryDog, which is a class that implements the ComicCharacter protocol:

var brian = AngryDog(nickName: "Brian")
var merlin = AngryDog(nickName: "Merlin")
brian.drawSpeechBalloon("Hello, my name is \(brian.nickName)")
brian.drawSpeechBalloon(merlin, message: "How do you do?")
merlin.drawThoughtBalloon("Who are you? I think.")

Tip

Bear in mind that when we work with protocols, we use them to specify...

Downcasting with protocols and classes


The ComicCharacter protocol defines one of the method requirements for the drawSpeechBalloon method with destination as an argument of the ComicCharacter type, which is the same type that the protocol defined. The following is the first line in our sample code that called this method:

brian.drawSpeechBalloon(merlin, message: "How do you do?")

We called the method defined within the AngryDog class because brian is an instance of AngryDog. We passed an AngryDog instance, merlin, to the destination argument. The method works with the destination argument as an instance that conforms to the ComicCharacter protocol; therefore, whenever we reference the destination variable, we will only be able to see what the ComicCharacter type defines.

We can easily understand what happens under the hood when Swift downcasts a type from its original type to a target type, such as a protocol to which the class conforms. In this case, AngryDog is downcast to ComicCharacter...

Treating instances of a protocol type as a different subclass


Now, we will take advantage of the possibility that Swift offers us to extend an existing class to add specific members. In this case, we will add an instance method to the previously defined AngryCat class. The following lines add the doSomethingWithAnAngryCat method to the existing AngryCat class:

public extension AngryCat {
    public func doSomethingWithAnAngryCat(cat: AngryCat) {
        if let angryCatAlien = cat as? AngryCatAlien {
            angryCatAlien.appear()
        } else if let angryCatKnight = cat as? AngryCatKnight {
            angryCatKnight.unsheathSword()
        } else if let angryCatWizard = cat as? AngryCatWizard {
            print("My spell power is \(angryCatWizard.spellPower)")
        } else {
            print("This AngryCat doesn't have cool skills.")
        }
    }
}

The doSomethingWithAnAngryCat method receives an AngryCat instance (cat) and uses the conditional type casting operator (as?) to...

Specifying requirements for properties


In the previous chapter, we worked with simple inheritance to specialize animals. Now, we will go back to this example and refactor it to use protocols that allow us to take advantage of multiple inheritance.

The decision to work with contract-based programming appears with a new requirement, which is the need to make domestic birds and other domestic animals different from domestic mammals which talk and have a favorite toy. We already had a talk method and a favoriteToy property defined in the DomesticMammal class. However, now that we know how to work with protocols, we don't want to introduce duplicate code, and we want to be able to generalize what is required to be domestic, with a specific protocol for this.

We will define the following six protocols and take advantage of inheritance in protocols; that is, we will have protocols that inherit from other protocols, as follows:

  • AbstractAnimal: This defines the requirements for an animal.

  • AbstractDomestic...

Specifying requirements for methods


The AbstractAnimal protocol requires two type methods: printALeg and printAChild. As explained with the type property requirements, we can only use the static keyword to specify a type method requirement, but we can use either static or class when we implement the type method in the class that conforms to the protocol. The usage of the static keyword doesn't have the same meaning that this keyword has when we use it in classes; that is, we can still declare type methods that can be overridden in the classes that conform to the protocol by declaring them with the class keyword in the respective classes. The following line shows the type method requirement for printALeg:

static func printALeg()

The protocol defines three parameterless methods: printLegs, printChildren, and printAge. The method requirements use the func keyword followed by the method name and its arguments, as if we were writing the method declaration for a class but without the method body...

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 AbstractAnimal protocol:

public class Animal: AbstractAnimal {
    public class var numberOfLegs: Int {
        get {
            return 0;
        }
    }
    public class var averageNumberOfChildren: Int {
        get {
            return 0;
        }
    }
    
    public class var abilityToFly: Bool {
        get {
            return false;
        }
    }
    
    public var age: Int
    
    init(age : Int) {
        self.age = age
        print("Animal created")
    }
    
    public class func printALeg() {
        preconditionFailure("The pringALeg method must be overriden")
    }
    
    public...

Exercises


Create the following protocols to solve the problem explained in Chapter 1, Objects from the Real World to Playground:

  • AbstractShape

  • AbstractRegularPolygon

  • AbstractEllipse

  • AbstractRectangle

  • AbstractCircle

After you create the protocols, create the classes that implement them based on the specifications explained in Chapter 1, Objects from the Real World to Playground.

The following table summarizes the list of protocols to which each of the classes you must create will conform:

Class name

Conforms to the following protocol(s)

Shape

AbstractShape

Rectangle

AbstractRectangle and AbstractShape

RegularPolygon

AbstractRegularPolygon and AbstractShape

Ellipse

AbstractEllipse and AbstractShape

Circle

AbstractCircle and AbstractShape

EquilateralTriangle

AbstractRegularPolygon and AbstractShape

Square

AbstractRegularPolygon and AbstractShape

RegularHexagon

AbstractRegularPolygon and AbstractShape

Test your knowledge


  1. A class can conform to:

    1. Only one protocol.

    2. One or more protocols.

    3. A maximum of two protocols.

  2. When a class conforms to a protocol:

    1. It cannot inherit from a class.

    2. It can inherit from an abstract class.

    3. It can also inherit from a class.

  3. A protocol:

    1. Can inherit from another protocol.

    2. Can inherit from a class.

    3. Cannot inherit from another protocol.

  4. A protocol:

    1. Is a type.

    2. Is a method.

    3. Is the base class for other classes.

  5. When we specify a protocol as the type for an argument:

    1. We can use any type method that conforms to the specified protocol as an argument.

    2. We can use any protocol that conforms to the specified protocol as an argument.

    3. We can use any instance of a class that conforms to the specified protocol as an argument.

Summary


In this chapter, you learned about the declaration and combination of multiple blueprints to generate a single instance. We declared protocols with different types of requirements. Then, we created many classes that conformed to these protocols.

We worked with type casting to understand how protocols work as types. Finally, we combined protocols with classes to take advantage of multiple inheritance in Swift. We combined inheritance for protocols and classes.

Now that you have learned about protocols, multiple inheritance, and contract-based programming, we are ready to maximize code reuse with generic code and parametric polymorphism.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Object???Oriented Programming with Swift 2
Published in: Jan 2016Publisher: ISBN-13: 9781785885693
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Gaston C. Hillar

Gaston C. Hillar is Italian and has been working with computers since he was 8 years old. Gaston has a Bachelor's degree in computer science (graduated with honors) and an MBA. Currently, Gaston is an independent IT consultant and a freelance author who is always looking for new adventures anywhere in the world. He was a senior contributing editor at Dr. Dobb's, and has written more than a hundred articles on software development topics. He has received the prestigious Intel Black Belt Software Developer award eight times. He has written many articles about Java for Oracle Java Magazine. Gaston was also a former Microsoft MVP in technical computing. He lives with his wife, Vanesa, and his two sons, Kevin and Brandon.
Read more about Gaston C. Hillar