Reputation: 1865
I was thinking about the Validation checks in my app and I thought that calling ValidatorFactory on any model, that implements Validee, meaning saying which class is responsible for ValidatorCreation sounds sweet. But the code below doesn't work :(
Code:
struct Client: Validee {
typealias ValidatorFactoryClass = ClientValidator
}
protocol Validee {
associatedtype ValidatorFactoryClass: AbstractValidatorFactory
}
protocol Validator {
func validate() throws -> Void
}
protocol AbstractValidatorFactory {
associatedtype Model
static func create(fromModel model: Model) -> Validator
}
struct ValidatorFactory {
static func createValidator(fromModel model: Validee) -> Validator {
return model.ValidatorFactoryClass.create(fromModel: model)
}
}
struct ClientValidator : AbstractValidatorFactory {
typealias Model = Client
static func create(fromModel model: Model) -> Validator {
return ClientDeliveryAddressValidator(withModel: model)
}
}
struct ClientDeliveryAddressValidator: Validator {
typealias Model = Client
let client: Client
init(withModel client: Client) {
self.client = client
}
func validate() throws {
}
}
let client = Client()
do {
try ValidatorFactory.createValidator(fromModel: client).validate()
} catch {
// error handling here
}
But even if I forget about the Validator Factory and try to run the following code it doesn't work:
client.ValidatorFactoryClass.create(fromModel: client)
Why ?
Upvotes: 0
Views: 288
Reputation: 3169
If the problem you are having is due to compilation errors, your ValidatorFactory
struct needs modifying.
You can’t use a protocol as a type directly. You use it as a constraint on a type. This means than rather than having Validee
as a parameter type to ValidatorFactory.createValidator
, it is a constraint on that type. This change would give you:
struct ValidatorFactory<T:Validee> {
static func createValidator(fromModel model: T) -> Validator {
return model.ValidatorFactoryClass.create(fromModel: model)
}
}
This still has a problem because Swift cannot work out the relationship between the type T
and the parameter type for the call to create
. But the relationship exists in your code; you just need to make it explicit.
Changing ValidatorFactory
to this compiles for me. I have not tried running the code, however.
struct ValidatorFactory<T:Validee> {
static func createValidator(fromModel model: T) -> Validator {
return T.ValidatorFactoryClass.create(fromModel: model as! T.ValidatorFactoryClass.Model)
}
}
Edit:
Given that Validee
already knows about the factory, it would be simpler to change the design so Validee
knows about creating the Validator directly.
This would give you:
protocol Validee {
static func create(fromModel model: Self) -> Validator
}
protocol Validator {
func validate() throws -> Void
}
struct ValidatorFactory<T:Validee> {
static func createValidator(fromModel model: T) -> Validator {
return T.create(fromModel: model)
}
}
struct Client: Validee {
static func create(fromModel model: Client) -> Validator {
return ClientDeliveryAddressValidator(withModel: model)
}
}
struct ClientDeliveryAddressValidator: Validator {
typealias Model = Client
let client: Client
init(withModel client: Client) {
self.client = client
}
func validate() throws {
}
}
Upvotes: 1