Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Protocol-oriented programming in Swift

Protocol-oriented programming in Swift

Introduction to Protocol-oriented Programming in Swift and why to embrace it to make plug-compatible components in our application designs.

Avatar for Albert Hernández

Albert Hernández

May 30, 2016

Other Decks in Programming

Transcript

  1. let cheeseCake = CheeseCake() let oven = Oven() oven.cake =

    cheeseCake oven.turnOn() // Output: “ is cooked!”
  2. WE HAVE OBSERVED THE METRICS, MOST OF OUR CLIENTS ARE

    VEGAN. LET’S GO WITH CARROT CAKES INSTEAD. That hipster product owner
  3. class CarrotCake: Cake {} // ... let carrotCake = CarrotCake()

    let oven = Oven() oven.cake = carrotCake oven.turnOn() // Output: “ is cooked!”
  4. WE NEED TO PIVOT, TO DISRUPT THE BAKERY WORLD. WE

    SHOULD OFFER PIZZA AS WELL. That hipster product owner...
  5. TIGHT COUPLING class Oven { var cake: Cake? func turnOn()

    { cake?.cook() } } HARD TO MAINTAIN
  6. INHERITANCE HIERARCHIES class Cake { func cook() { print(" is

    cooked!") } } class CheeseCake: Cake {} HARD TO EXTEND
  7. IMPLEMENTATION IS A WHITE-BOX class Cake { func cook() {

    print(" is cooked!") } } class CheeseCake: Cake {} HARD TO REUSE even using proper encapsulation
  8. ▸Separation of the public interface from the implementation ▸Software defined

    in components which talk to each other using interfaces ▸Not new, AKA interface-based programming
 Probably popularized with Java
  9. ▸POP is at heart of Swift’s design public struct Array<Element>

    : CollectionType, MutableCollectionType, _DestructorSafeContainer //... public protocol CollectionType : Indexable, SequenceType { //... public protocol Indexable { //...
 public protocol SequenceType { //... extension SequenceType { //...
  10. ▸are shared boundaries across which information is passed ▸declare methods

    and properties that are required to be provided by its implementation/s ▸can be adopted by classes, structs and enums ▸can be inherited, one or multiple ▸protocol extensions ▸generics with associated types
  11. protocol Cookable { func cook() } protocol Edible { func

    eat() } protocol IngredientType: Cookable, Edible { var calories: Int { get } } struct Ingredient: IngredientType { let calories: Int func cook() { print(“") } func eat() { print(“") } }
  12. ▸from a design standpoint, an interface is a contract ▸when

    POP’ing we have plug-compatible objects (not tight to an implementation) ▸interfaces offer polymorphism independent of the inheritance hierarchy ▸reusability, maintainability, and extensibility
  13. protocol Cookable { func cook() } struct CarrotCake: Cookable {

    func cook() { print(" is cooked!") } } struct Pizza: Cookable { func cook() { print(" is cooked!") } } class Cake { func cook() print(" } } class CheeseCak REUSABILITY
  14. class Cake { func cook() { print(" is cooked!") }

    } extension Cake: Cookable {} EXTENSIBILITY
  15. protocol CookingMachine { var cookable: Cookable? { get set }

    func turnOn() } extension CookingMachine { func turnOn() { cookable?.cook() } } class Oven { var cake: Cak func turnOn() cake?.coo } } EXTENSIBILITY
  16. class Oven: CookingMachine { var cookable: Cookable? } BLACK-BOXED class

    Oven { var cake: Cak func turnOn() cake?.coo } } protocol Cookable { func cook() }
  17. let carrotCake: Cookable = CarrotCake() let cookingMachine: CookingMachine = Oven()

    cookingMachine.cake = carrotCake cookingMachine.turnOn() // Output: “ is cooked!”
  18. ▸Modeling data types ▸Abstraction of your instances source ▸Clean way

    to build-up mock objects (tests) ▸Dependency injection (provider) ▸Subclassing == code smelly ▸Detached architecture (clean, MVVM…) ▸A/B testing interfacing
  19. BUILD A FRAMEWORK THAT RETRIEVES A POSTAL ADDRESS GIVEN A

    GEOPOINT After POP’ing, our colleague PO
  20. protocol GeoPointType { var latitude: Double { get } var

    longitude: Double { get } } struct GeoPoint: GeoPointType { let latitude: Double let longitude: Double } struct MockGeoPoint: GeoPointType { let latitude: Double = Double.random(-90...90) let longitude: Double = Double.random(-180...180) } /* let's assume we've a Double extension with the method:
 static func random(range: Range<Int>) -> Double */
  21. /* CLPlacemark+PostalAddressType.swift */ extension CLPlacemark: PostalAddressType {} /* CLPlacemark.h */

    public class CLPlacemark : NSObject, NSCopying, NSSecureCoding { //... public var locality: String? { get } public var country: String? { get } //... }
  22. typealias RetrieveAddressCompletion = PostalAddressType? -> () protocol AddressDataSource { func

    retrieveAddress(geoPoint: GeoPoint, completion: RetrieveAddressCompletion?) } class MockAddressDataSource: AddressDataSource { var retrieveAddressResult: PostalAddressType? func retrieveAddress(geoPoint: GeoPoint, completion: RetrieveAddressCompletion?) { let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))) dispatch_after(delay, dispatch_get_main_queue()) { [weak self] in completion?(self?.retrieveAddressResult) } } }
  23. class AppleAddressDataSource: AddressDataSource { let geocoder: CLGeocoder init(geocoder: CLGeocoder) {

    self.geocoder = geocoder } func retrieveAddress(geoPoint: GeoPoint, completion: RetrieveAddressCompletion?) { let location = CLLocation(latitude: geoPoint.latitude, longitude: geoPoint.longitude) geocoder.reverseGeocodeLocation(location) { (placemarks, _) -> Void in let placemark = placemarks?.first completion?(placemark) } } }
  24. class AddressRepository { private let addressDataSource: AddressDataSource init(addressDataSource: AddressDataSource) {

    self.addressDataSource = addressDataSource } func retrieveAddress(geoPoint: GeoPoint, completion: RetrieveAddressCompletion?) { addressDataSource.retrieveAddress(geoPoint, completion: completion) } }
  25. ▸loosely coupled architecture with white- boxed implementation ▸maintainable: if we

    need to switch our data source implementation all our repo tests should remain GREEN ▸we can extend AddressRepository (but we’d do it POP’d ) ▸we can reuse this code in other projects