Так как вы отметили в комментариях, что все типы будут подклассами некоторого супертипа, тогда этот супертип может обрабатывать всю диспетчеризацию. В Какао это довольно распространенный шаблон, известный как кластер классов.
class SuperA {
enum SuperAError: Error {
case cannotConstruct
}
static func create(className: String, argName: String, argValue: String) throws -> SuperA {
switch className {
case "A":
guard argName == "val",
let value = Int(argValue)
else { throw SuperAError.cannotConstruct }
return A(val: value)
default:
throw SuperAError.cannotConstruct
}
}
}
Теперь мне не особенно нравится этот подход. Этот вид подклассов, как правило, плохой Swift. Swift подходит для классов, когда вам требуется ссылочный тип, но он не поддерживает создание подклассов. Я бы сделал это с помощью протокола Buildable и Builder:
enum BuildableError: Error {
case unknownType
case badParameters
}
protocol Buildable {
init(argName: String, argValue: String) throws
// ... and the rest of the methods you require ...
}
struct A {
var val: Int
}
extension A: Buildable {
init(argName: String, argValue: String) throws {
guard argName == "val", let value = Int(argValue) else {
throw BuildableError.badParameters
}
self.init(val: value)
}
}
final class Builder {
var buildables: [String: Buildable.Type] = [:]
func build(className: String, argName: String, argValue: String) throws -> Buildable {
guard let buildable = buildables[className] else {
throw BuildableError.unknownType
}
return try buildable.init(argName: argName, argValue: argValue)
}
}
let builder = Builder()
builder.buildables["A"] = A.self
builder.build(className: "A", argName: "val", argValue: "4")
Если это приводит к дублированию кода, существуют простые способы решения этой проблемы с другими протоколами. Например, если многие из ваших типов имеют init(val: Int)
, они могут поделиться кодом с другим протоколом:
protocol ValIntBuildable: Buildable {
init(val: Int)
}
extension ValIntBuildable {
init(argName: String, argValue: String) throws {
guard argName == "val", let value = Int(argValue) else {
throw BuildableError.badParameters
}
self.init(val: value)
}
}
extension A: ValIntBuildable {}