Skip to content

Instantly share code, notes, and snippets.

@ajonno
Created June 24, 2016 06:21
Show Gist options
  • Save ajonno/3d71af7402da7c8b239eea6982c96b9d to your computer and use it in GitHub Desktop.
Save ajonno/3d71af7402da7c8b239eea6982c96b9d to your computer and use it in GitHub Desktop.
Example of Repository pattern using Swift
// credit -> http://acqui-hire.me/dependency-injection-with-the-cake-pattern-in-swift/
public struct User {
public let username: String
public let password: String
}
public protocol UserRepository {
func findByUsername(username: String) -> User?
}
public protocol UserRepositoryComponent {
static var userRepository: UserRepository { get }
static func createUserRepository() -> UserRepository
}
public protocol UserService {
func authenticate(username: String, password: String) -> User?
}
public protocol UserServiceComponent {
static var userService: UserService { get }
static func createUserService() -> UserService
}
private struct StaticUserRepository: UserRepository {
private static let users = [
"admin": User(username: "admin", password: "admin"),
"alice": User(username: "alice", password: "123")
]
private func findByUsername(username: String) -> User? {
return StaticUserRepository.users[username]
}
}
public protocol StaticUserRepositoryComponent: UserRepositoryComponent {}
extension StaticUserRepositoryComponent {
public static func createUserRepository() -> UserRepository {
return StaticUserRepository()
}
}
private struct DefaultUserService: UserService {
private let userRepository: UserRepository
private init(userRepository: UserRepository) {
self.userRepository = userRepository
}
private func authenticate(username: String, password: String) -> User? {
guard let user = userRepository.findByUsername(username) else {
print("No user found with username: \(username)")
return nil
}
guard user.password == password else {
print("Username and password do not match for username: \(username)")
return nil
}
return user
}
}
public protocol DefaultUserServiceComponent: UserServiceComponent {}
extension DefaultUserServiceComponent where Self: UserRepositoryComponent {
public static func createUserService() -> UserService {
return DefaultUserService(userRepository: userRepository)
}
}
public enum AppContext: StaticUserRepositoryComponent, DefaultUserServiceComponent {
public static let userRepository = AppContext.createUserRepository()
public static let userService = AppContext.createUserService()
}
// THIS //
if let user = AppContext.userService.authenticate("alice", password: "123") {
print("Thank you for logging in, \(user.username)!")
} else {
print("Please check your username and password")
}
// OR //
public typealias ContextType = protocol<UserRepositoryComponent, UserServiceComponent>
public struct Context {
private let type: ContextType.Type
public var userRepository: UserRepository {
return type.userRepository
}
public var userService: UserService {
return type.userService
}
public init(type: ContextType.Type) {
self.type = type
}
}
let context = Context(type: AppContext.self)
if let user = context.userService.authenticate("alice", password: "123") {
print("Thank you for logging in, \(user.username)!")
} else {
print("Please check your username and password")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment