This repository demonstrates how to resolve circular dependencies in a Swift project by leveraging modular design. The example uses two main modules, Store and Travel, and showcases how to split modules into shared protocols and implementations for better decoupling.
- Defines lightweight shared protocols for the
Travelfunctionality. - Provides abstractions that other modules, like
Store, can depend on.
- Contains the actual implementation of
Travelfunctionality. - Depends on
TravelServicefor protocol definitions.
- Defines shared protocols for the
Storefunctionality. - Relies on abstractions to integrate with other modules, like
Travel.
- Implements the core
Storefunctionality. - Depends on
StoreServiceandTravelServicefor protocols, ensuring no circular dependency.
- Integrates
TravelandStoreby creating instances and injecting dependencies at runtime.
- Decoupling: Ensures
StoreandTravelmodules are loosely coupled, allowing independent updates. - Dependency Inversion: Modules depend on abstractions (
StoreService,TravelService) instead of concrete implementations. - Testability: Simplifies unit testing by enabling mock implementations of protocols.
- Modularity: Improves build times and scalability for larger projects.
The Main App creates a StoreCore (from Store) and a TravelCore (from Travel). It injects the StoreCore into TravelCore using the StoreService protocol, facilitating seamless communication.
import Travel
import Store
let store = StoreCore() // Implements StoreService
let travelService = TravelCore(store: store) // Uses StoreService
// Example usage
travelService.book()