First, you'll need to define a common protocol or interface that all your objects share. This will ensure all of our adapters share the same interface.
In this particular scenario, we simply want to track events with additional and optional custom properties. It can be defined as follows:
public protocol Tracking {
func record(event: String)
func record(event: String, properties: [String: String]?)
}
Thanks to protocol extensions, it is also possible to define the default implementation of tracking with empty properties:
extension Tracking {
func record(event: String) {
record(event: event, properties: nil)
}
}
Now that the base tracking protocol is defined, it is possible to expose the shared tracker:
public class Tracker: Tracking {
Set up a singleton that can be accessed across the program, as follows:
public static let shared = Tracker()
Keep a reference to the tracking adapter:
private var trackingAdapter: Tracking!
Next, declare a set method, to register the tracking adapter:
public func set(trackingAdapter: Tracking) {
self.trackingAdapter = trackingAdapter
}
Declare the conformance to tracking, so it is possible to forward the calls to the private adapter:
public func record(event: String, properties: [String : String]?) {
trackingAdapter.record(event: event, properties: properties)
}
}
This is optional, and not part of the adapter design pattern. It will help when referencing the specialized analytics tracker across the program. It also forwards calls to the Tracking class.