Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Designing Software with Swift (Part IV): Functional Type-based Design

DZone's Guide to

Designing Software with Swift (Part IV): Functional Type-based Design

We've covered protocol and generic design options. How does functional programming stack up? Find out.

· Mobile Zone
Free Resource

Download this comprehensive Mobile Testing Reference Guide to help prioritize which mobile devices and OSs to test against, brought to you in partnership with Sauce Labs.

So far, we've looked over protocol-centric and generic type-based design. Let's expand our pallete by bringing in Swift's functional capabilities.

Functional programming has gone through it's ups and downs, no doubt. At one time, it was an esoteric programming practice confined to the AI community. Since then, some aspects of functional programming have found their way into more mainstream languages, like Swift. So, what would our observer look like using functional techniques?

The third version, using generic typing and Swift’s functional capabilities:

class Subject<K: Hashable,T> {

  var observers: [K: (T) -> Void] = [:]

  func attach(key: K, observer: (T) -> Void) {
    observers[key] = observer
  }

  func detach(key: K) {
    observers.removeValueForKey(key)
  }

  func notify(msg: T) {
    for (_, function) in observers {
      function(msg)
    }
  }
}

class GeneratingObserver {

  let name : String = String(arc4random_uniform(10000))

  func generateClosure() -> (String) -> Void {
    return {(msg: String) -> Void in
      print("GeneratingObserver: \(msg)")
    }
  }
}

class FunctionObserver<T> {

  let name : String = String(arc4random_uniform(10000))

  func notify(msg: T) {
    print("FunctionObserver: \(msg)")
  }
}

func observer<String>(msg: String) {
  print("observer: \(msg)")
}

var stringClosure = {(msg: String) -> Void in
  print("stringClosure: \(msg)")
}


And running this particular example is equally terse:

var subject = Subject<String, String>()
var ob1 = GeneratingObserver()
var ob2 = FunctionObserver<String>()

subject.attach(ob1.name, observer: ob1.generateClosure())
subject.attach(ob2.name, observer: ob2.notify)
subject.attach("observer", observer: observer)
subject.attach("stringClosure", observer: stringClosure)
subject.attach("anon closure") {(msg: String) -> Void in
  print("anon closure 2: \(msg)")
}


In this case, we’ve replaced our Observer object with a function, of type (T) -> Void, and we’ve specialized our generic function to the type (String) -> Void. This gives us tremendous flexibility with respect to what we submit as an observer, In our example, we use a generated function, a class method, a global function, and two different kinds of closures. All of these are compatible with the defined interface, and work just fine.

Also notice that our code has become much simpler in this final example, and we have even less of it this time than we did in Part III. Smaller amounts of simple code take less time to develop, less time to test, and less time to maintain. All this adds up to lower cost - a good thing!

So now we have three different designs for the observer design pattern. One is very protocol-centric, one does away with protocol in favor of generics, and the final one takes full advantage of Swift’s generics and functional capabilities. What are the advantages and disadvantages of each? We'll cover this in the final installment of the series.

Analysts agree that a mix of emulators/simulators and real devices are necessary to optimize your mobile app testing - learn more in this white paper, brought to you in partnership with Sauce Labs.

Topics:
swift ,design ,pattern

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}