Visualizing the dependency graph
There are different types of dependency you can represent in a dependency diagram using different annotations, lines, and arrows.
Here are the main ones:
A solid line with an empty head denotes that a class inherits from another class.
For example:
class MyViewController: UIViewController { ... }
The MyViewController
class inherits from the UIViewController
class, or the MyViewController
"is a" subtype of UIViewController
.
A dashed line with an empty head denotes that a component conforms/implements a protocol/abstract interface.
For example:
protocol HTTPClient { ... }
class URLSessionHTTPClient: HTTPClient { ... }
The URLSessionHTTPClient
conforms to the HTTPClient
protocol.
A solid line with a filled head denotes a strong dependency.
When a type instance depends on another type instance to exist, it's considered a stronger dependency, such as Association, Aggregation, and Composition.
For example:
class RemoteFeedLoader {
private let client: HTTPClient
init(client: HTTPClient) {
self.client = client
}
}
The RemoteFeedLoader
has an HTTPClient
.
You cannot instantiate a RemoteFeedLoader
without an HTTPClient
instance. The code wouldn't even compile. So that's a strong dependency.
The RemoteFeedLoader
depends on an HTTPClient
to exist.
A dashed line with a filled head denotes a weak dependency.
It's important to note that a type can depend on and use another but still work without one.
For example:
class RemoteFeedLoader {
func load(with client: HTTPClient) {
client.doSomething()
}
}
The RemoteFeedLoader
has a source code dependency to the HTTPClient
because it references and uses it. But it doesn't require an HTTPClient
instance to exist.
You can create a RemoteFeedLoader
without an HTTPClient
.
That's considered a weaker dependency, but still a dependency!
The RemoteFeedLoader
uses an HTTPClient
dependency in the load method. But it doesn't have one. It must be provided as a parameter.