Recentemente ho lavorato a una classe di servizio di rete riutilizzabile per un'app per iOS di servizi di aggregazione. Questa classe dovrebbe riprovare una richiesta non riuscita se è stata causata da un token utente scaduto. Inoltre, questa classe verrà utilizzata tra più appaltatori, che creeranno i servizi aggregati.
Poiché gli appaltatori potrebbero utilizzare diversi metodi di autenticazione, creo un'interfaccia / un protocollo per la classe che gestirà l'autenticazione dell'utente. Ecco un esempio del mio lavoro (in Swift):
BaseNetworkService.swift
class BaseNetworkService {
/**
Request headers that will be used by this instance.
*/
internal var requestHeaders = ["Content-Type": "application/json"]
/**
Request GET method to 'URL' with passed 'parameters'. Will send success response
in 'next' and failure in 'error' event of returned 'RACSignal' instance.
*/
internal func GET(URL: String, parameters: [String: AnyObject]) -> RACSignal {
// method implementation here
}
// Rest of HTTP methods here
}
AuthenticatedNetworkService.swift
class AuthenticatedNetworkService: BaseNetworkService {
/**
Used to retrieve authentication-related request headers
and refresh expired user token.
*/
private var authService: AuthenticationProtocol
init(authService: AuthenticationProtocol) {
self.authService = authService
}
/**
Request GET method to 'URL' with passed 'parameters'. Will send success response
in 'next' and failure in 'error' event of returned 'RACSignal' instance.
- note: If the request fails because of expired user token, this instance will
refresh current user token, and retry it once again.
*/
override func GET(URL: String, parameters: [String: AnyObject]) -> RACSignal {
// method implementation here
}
// Rest of HTTP methods here
}
AuthenticationProtocol.swift
protocol AuthenticationProtocol {
/**
Stores authentication header name in the 'key', and its value in its
corresponding 'value'.
*/
internal var authenticationHeaders: [String: String] { get }
/**
Checks whether passed 'error' caused by expired user token or not.
*/
func isErrorCausedByExpiredToken(error: NSError) -> Bool
/**
Refresh this instance's 'authenticationHeaders'. It send 'next:' event from
returned 'RACSignal' if the process succeeds, and 'error:' otherwise.
*/
func refreshAuthenticatioHeaders() -> RACSignal
}
Leggevo su Design Patterns mentre lavoravo su questo, e ho creato una classe tipo Factory per creare AuthenticatedNetworkService per i servizi aggregati. Qualcosa intorno a questo:
class AuthenticatedNetworkServiceFactory {
/**
Returns network service for Pizza Delivery service.
*/
class func PizzaDeliveryNetworkService() -> AuthenticatedNetworkService {
let authService = PizzaDeliveryAuthenticationService()
return AuthenticatedNetworkService(authService: authService)
}
/**
Returns network service for Quick Laundry service.
*/
class func QuickLaundryNetworkService() -> AuthenticatedNetworkService {
let authService = QuickLaundryAuthenticationService()
return AuthenticatedNetworkService(authService: authService)
}
/**
Returns network service for Cab Finder service.
*/
class func CabFinderNetworkService() -> AuthenticatedNetworkService {
let authService = CabFinderAuthenticationService()
return AuthenticatedNetworkService(authService: authService)
}
}
Eppure, dopo aver rivisitato il libro GoF, ho scoperto che il pattern Factory aveva lo scopo di restituire sottoclassi anziché una classe principale. Dato che stavo restituendo la classe principale ( AuthenticatedNetworkService
), la AuthenticatedNetworkServiceFactory
potrebbe essere considerata una Fabbrica? O era solo una lezione di aiuto?