Ambient Context

The final pattern, Ambient Context, is similar to the Singleton.

We still have a single instance as a static variable, but the class has multiple subclasses with different behaviors, and each static variable is writeable with a static function:

class Analytics {
static private(set) var instance: Analytics = NoAnalytics()
static func setAnaylics(analitics: Analytics) {
self.instance = analitics
}
func track(event: Event) {
fatalError("Implement in a subclass")
}
}

class NoAnalytics: Analytics {
override func track(event: Event) {}
}

class GoogleAnalytics: Analytics {
override func track(event: Event) {
//...
}
}

class AdobeAnalytics: Analytics {
override func track(event: Event) {
//...
}
}

struct Event {
//...
}

This pattern should be used only for universal dependencies, representing some cross-cutting concernssuch as analytics, logging, and times and dates.

This pattern has some advantages. The dependencies are always accessible and don't need to change the API.
It works well for cross-cutting concerns, but it doesn't fit in other cases when the object isn't unique.
Also, it makes the dependency implicit and it represents a global mutable state that sometimes can lead to issues that are difficult to debug.