In this article, we going to take a look at some common issues with application design. We’ll find out the limitation of classical Object-Oriented Programming and how we can address those using a different approach. In this case, we’ll examine refactoring code with POP approach.
Getting Started
Protocol-Oriented Programming is a new programming paradigm ushered in by Swift 2.0. In the Protocol-Oriented approach, we start designing our system by defining protocols. We rely on new concepts: protocol extensions, protocol inheritance, and protocol compositions. The paradigm also changes how we view semantics. In Swift, value types are preferred over classes. However, objeaoriented concepts don’t work well with structs and enums: a struct cannot inherit from another struct, neither can an enum inherit from another enum. So inheritancefa - one of the fundamental object-oriented concepts - cannot be applied to value types. On the other hand, value types can inherit from protocols, even multiple protocols. Thus, with POP, value types have become first class citizens in Swift.
The aims of this project are to examine the POP paradigm in current project and to compare POP with classical OOP.
Classical Inheritance OOP
Inheritance is a useful technique in OOP but it has some limitation in representing the complexity required by relationships among application entities. To demonstrate, let’s start with class diagram of animal:
In above scenario, our animal don’t seem to be fit well with the inheritance pattern. The signification of this issue are duck and exocoetidae. Duck is not fish but they can swim and exocoetidae is not bird but they can fly. This counterexample to notion that it is not possible to implement swim() method of Fish class inside Duck and the same with fly()** method of Bird class inside exocoetidae*.
A possible solution would be to duplicate the required code for each new subclass. It looks easy, but then we need to deal with a lot of code duplication. In order to avoid that, we put these methods to closest super class. But this will make complex base class.
Better Approach POP
Swift, just like many other programming languages, does not support multiple inheritance. The previous approach, you’d have to keep adding new functionality to your superclass or otherwise create new intermediary class, thereby complicating issue. In new approach, we’re going to use Protocol to solve this issue. Protocols serve as blueprints: they tell us what adopters shall implement, but you can’t provide implementation within a protocol. Luckily, there is another way: protocol extensions are the way to go! In Swift, you can extend a protocol and provide default implementation for methods, computed properties, subscripts and convenience initializers. The following class diagram show the changes in implementation:
Swift does not allow multiple inheritance for classes. However, Swift types can adopt multiple protocols. In below diagram, we use 3 protocols Swimable, Flyable, Eatable. Now, Duck and exocoetidae class adopt all 3 protocols, other class like Tuna only adopts Swimable and Eatable protocols. This design not only is more flexible than squeezing all the required functionality into a monolithic base class but also works for value types.
Refactoring Our Project
In current project, there are 2 files can be refactor using POP : MapAnnotation and FeedViewModel. Both of them have image() method to get the icon image but FeedViewModel is a struct , MapAnnotation is subclass of MKAnnotation. You can not use a superclass in this case. The following diagram show the current structure of 2 files:
In this case, POP and Protocol extension are the best choice. Also, to make feed screen synchronize with map screen, we will display the icon inside a round bubble like map screen. This following class diagram show how to solve above problem with new approach:
You create 2 new protocols GetableIconImage and GetableTintColor and their protocol extension to implement image() and makerTintColor() methods. Then, MapAnnotation and FeedViewModel are going to adopt them.
Go to File\New\File…, select iOS\Source\Swift File template and click Next. Name the file GetableIconImage and click Create to save the file. Add the following contents:
1 | import Foundation |
Next, Go to File\New\File…, select iOS\Source\Swift File template and click Next. Name the file GetableTintColor and click Create to save the file. Add the following contents:
1 | import Foundation |
Finally, let your MapAnnotation class and FeedViewModel struct adopt both protocol. Your MapAnnotation.swift file should look like following:
1 | import UIKit |
And, your FeedViewModel.swift file should look like following:
1 | import Foundation |
Build and run project, your feed screen should look like this:
Conclusions
In this article, project has been refactored using POP paradigm. You have figured out the common issue with OOP and the new approach with POP. Based on these findings, you can find the better class hierarchy that clean and easy to maintain.
Here is the final project of this part.