POP encourages us to develop protocols and extend them instead of classes and inheritance. POP is new in the Objective-C and Swift development community, but what it provides is not very different from the concept of Abstract
classes in languages such as Java and C# and pure-virtual
functions in C++.
In Swift, classes, structs, and enumerations can conform to protocols. This makes protocols more usable because inheritance does not work for structs and enumerations.
In this section, we will explore POP paradigms. To start with, we will look at an example:
protocol UserProtocol { func greet(name: String) -> String func login(username: String, password:String) -> Bool }
This protocol defines two functions to be implemented by the struct, enumeration, or classes that need to conform to this protocol.
Protocol composition allows types to conform to more than one protocol. This is one of the many advantages that POP has over OOP. With OOP, a class can have only one superclass, which can lead to very monolithic super classes. With POP, we are encouraged to create multiple smaller protocols with very specific requirements.
Protocol extensions are one of the most important parts of the POP paradigm. They allow us to add functionality to all types that conform to a given protocol. Without protocol extensions, if we had common functionality that was necessary for all types that conformed to a particular protocol, then we would need to add that functionality to each type. This would lead to large amounts of duplicated code. The following example extends our protocol by adding a logout
method and its implementation; thus any struct, enum or class that conforms to UserProtocol
will have the logout
functionality:
extension UserProtocol { func logout(userName: String) -> Bool { return true } }
Protocol inheritance is where one protocol can inherit the requirements from one or more other protocols, as shown in the following code:
protocol MobileAppUserProtocol: UserProtocol { }
MobileAppUserProtocol
inherits from UserProtocol
so it will have all the defined and extended methods.
Associated types can be used to make our protocols work with generic types:
protocol MobileAppUserProtocol: UserProtocol { associatedtype applicationModuleList func listSelectedModules() -> [applicationModuleList] }
The following code presents an example of protocol conformance with associated type usage:
enum MobileAppUserType: MobileAppUserProtocol { case admin case endUser func greet(name: String) -> String { switch self { case .admin: return "Welcome (name) - You are Admin" case .endUser: return "Welcome (name)!" } } func login(username: String, password:String) -> Bool { return true } func listSelectedModules() -> [String] { return ["Accounting", "CRM"] } }
Then we can create a new mobile user as follows:
let mobileUser: MobileAppUserType = MobileAppUserType.Admin mobileUser.logout("cindy") mobileUser.listSelectedModules()
POP minimizes the inheritance and subclassing necessities by enabling us to conform to protocols and extend them with default implementations.