Swift 有什么问题吗?但是混凝土返回了一些具体的东西

Swift 有什么问题吗?但是混凝土返回了一些具体的东西,swift,oop,Swift,Oop,我相信我已经解决了这个问题,感谢当前的1点答案和泛型。我将更新下面的答案并将其添加到其中。谢谢 正在尝试创建命令总线 我正在努力用Swift创建一个命令总线。我现在遇到的问题是,我试图使这个东西足够通用,以处理不同的命令,但在许多情况下,我必须返回一个Any,这意味着我必须一直执行代码检查,我不确定我能做些什么 代码 最后,下面是命令总线,它基本上只是将给定给它的命令映射到处理程序并返回它。没有什么特别或复杂的 struct CommandBus { public let contain

我相信我已经解决了这个问题,感谢当前的1点答案和泛型。我将更新下面的答案并将其添加到其中。谢谢

正在尝试创建命令总线 我正在努力用Swift创建一个命令总线。我现在遇到的问题是,我试图使这个东西足够通用,以处理不同的命令,但在许多情况下,我必须返回一个
Any
,这意味着我必须一直执行代码检查,我不确定我能做些什么

代码 最后,下面是命令总线,它基本上只是将给定给它的命令映射到处理程序并返回它。没有什么特别或复杂的

struct CommandBus
{
    public let container: Container

    /// Added as closures so the commands are only resolved when requested
    private func commandMap() -> Array<[String: () -> (Any)]>
    {
        // TestCommand implements an empty protocol CommandProtocol
        return [
            [String(describing: TestCommand.self): { self.container.resolve(TestCommandHandler.self)! }]
        ]
    }

    /// Dispatch a command to the relevant command handler
    public func dispatch(_ command: Command) -> Any
    {
        let map = self.commandMap()
        let commandName = String(describing: command.self)
        let element = map.enumerated().first(where: { $0.element.keys.first == commandName })
        let elementIndex = map.index(element!.offset, offsetBy: 0)
        let commandHandler: CommandHandler = map[elementIndex].first!.value() as! CommandHandler

        return commandHandler.execute(command)!
    }
}

associatedtype
是您问题的答案:

protocol Command { }

protocol CommandHandler {
    associatedtype CommandType: Command // the concrete `CommandType` must conform to `Command`
    associatedtype ReturnType           // each handler will define what the return type is

    func execute(_ command: CommandType) -> ReturnType?
}

struct TestCommand: Command {
    public let value = 1
}

struct TestCommandHandler: CommandHandler {
    typealias CommandType = TestCommand
    typealias ReturnType = Int

    public func execute(_ command: CommandType) -> ReturnType? {
        // now `command` is of type `TestCommand` and the return value is `Int?`
        return 42
    }
}

我不确定你的
命令总线
应该做什么,所以我跳过了你问题的这一部分。

不确定这是否是你想要的,因为我真的不明白你想要实现什么,但看看我编写的这个操场代码:

import Foundation

protocol CommandProtocol {

    associatedtype Handler: CommandHandlerProtocol
    associatedtype Result

}

protocol CommandHandlerProtocol {

    associatedtype Command: CommandProtocol

    func execute(_ command: Command) -> Command.Result
    init()

}

class IntCommand: CommandProtocol {

    typealias Handler = IntCommandHandler
    typealias Result = Int
}

class IntCommandHandler: CommandHandlerProtocol {

    typealias Command = IntCommand

    func execute(_ command: Command) -> Command.Result {
        return 5
    }

    required init() { }
}

class StringCommand: CommandProtocol {

    typealias Handler = StringCommandHandler
    typealias Result = String
}

class StringCommandHandler: CommandHandlerProtocol {

    typealias Command = StringCommand

    func execute(_ command: Command) -> Command.Result {
        return "Hello!"
    }

    required init() { }
}

class CommandBus {

    public var map: [String: Any] = [:]

    func dispatch<T: CommandProtocol>(_ command: T) -> T.Handler.Command.Result {
        let handlerClass = map[String(describing: type(of: command))] as! T.Handler.Type
        let handler = handlerClass.init() as T.Handler
        return handler.execute(command as! T.Handler.Command)
    }

}

let commandBus = CommandBus()
commandBus.map[String(describing: IntCommand.self)] = IntCommandHandler.self
commandBus.map[String(describing: StringCommand.self)] = StringCommandHandler.self

let intResult = commandBus.dispatch(IntCommand())
print(intResult)

let stringResult = commandBus.dispatch(StringCommand())
print(stringResult)

您可以做的第一件事不是将所有代码的空格加倍;)在某些情况下,你希望每个作业都是直接相邻的,而不是相互关联的?这将更难阅读?难读的是滚动2个屏幕长度,10行代码。嗯,这样我可以把5个let放在一起,但仍然有一个滚动。我会把你的反馈带到船上,这样就可以把代码分成块,这样就没有滚动了。如果您输入了除编码标准以外的任何内容,我们将不胜感激:)我没有,否则我会回答:p
CommandBus
-您传递
dispatch()
一个
命令的实例,它会找到正确的
CommandHandler
类,实例化它,然后调用execute。它如何找到这个处理程序?开发人员必须将命令=>处理程序放在
commandMap
中。这6个let所做的全部工作就是搜索数组键中的命令,然后返回作为处理程序的值。它只是命令和它的处理程序之间的映射器。现在的问题是我的
CommandBus
无法返回
CommandHandler
的实例,因为我得到了以下错误:>协议“CommandHandler”只能用作泛型约束,因为它具有自身或关联的类型要求!我看到您这样做是为了让开发人员在运行时而不是编译时注册命令。协议中有
init()
的原因吗?有没有办法不提供init?因为init可能需要不同的参数,具体取决于处理程序。好的,您可以更改映射以实际使用初始化的处理程序,而不是处理程序类型。这样你就可以不用初始化了。但不确定编译时映射是什么意思。。。让我添加一个带有处理程序实例的示例,而不是需要初始化的类型。感谢Mihai的努力和一个很好的答案!这是非常有用的,正是我想要的:)赏金是你的。
protocol Command { }

protocol CommandHandler {
    associatedtype CommandType: Command // the concrete `CommandType` must conform to `Command`
    associatedtype ReturnType           // each handler will define what the return type is

    func execute(_ command: CommandType) -> ReturnType?
}

struct TestCommand: Command {
    public let value = 1
}

struct TestCommandHandler: CommandHandler {
    typealias CommandType = TestCommand
    typealias ReturnType = Int

    public func execute(_ command: CommandType) -> ReturnType? {
        // now `command` is of type `TestCommand` and the return value is `Int?`
        return 42
    }
}
import Foundation

protocol CommandProtocol {

    associatedtype Handler: CommandHandlerProtocol
    associatedtype Result

}

protocol CommandHandlerProtocol {

    associatedtype Command: CommandProtocol

    func execute(_ command: Command) -> Command.Result
    init()

}

class IntCommand: CommandProtocol {

    typealias Handler = IntCommandHandler
    typealias Result = Int
}

class IntCommandHandler: CommandHandlerProtocol {

    typealias Command = IntCommand

    func execute(_ command: Command) -> Command.Result {
        return 5
    }

    required init() { }
}

class StringCommand: CommandProtocol {

    typealias Handler = StringCommandHandler
    typealias Result = String
}

class StringCommandHandler: CommandHandlerProtocol {

    typealias Command = StringCommand

    func execute(_ command: Command) -> Command.Result {
        return "Hello!"
    }

    required init() { }
}

class CommandBus {

    public var map: [String: Any] = [:]

    func dispatch<T: CommandProtocol>(_ command: T) -> T.Handler.Command.Result {
        let handlerClass = map[String(describing: type(of: command))] as! T.Handler.Type
        let handler = handlerClass.init() as T.Handler
        return handler.execute(command as! T.Handler.Command)
    }

}

let commandBus = CommandBus()
commandBus.map[String(describing: IntCommand.self)] = IntCommandHandler.self
commandBus.map[String(describing: StringCommand.self)] = StringCommandHandler.self

let intResult = commandBus.dispatch(IntCommand())
print(intResult)

let stringResult = commandBus.dispatch(StringCommand())
print(stringResult)
protocol CommandHandlerProtocol {

    associatedtype Command: CommandProtocol

    func execute(_ command: Command) -> Command.Result

}

class CommandBus {

    private var map: [String: Any] = [:]

    func map<T: CommandProtocol>(_ commandType: T.Type, to handler: T.Handler) {
        map[String(describing: commandType)] = handler
    }

    func dispatch<T: CommandProtocol>(_ command: T) -> T.Handler.Command.Result {
        let handler = map[String(describing: type(of: command))] as! T.Handler
        return handler.execute(command as! T.Handler.Command)
    }

}

let commandBus = CommandBus()
commandBus.map(IntCommand.self, to: IntCommandHandler())
commandBus.map(StringCommand.self, to: StringCommandHandler())

let intResult = commandBus.dispatch(IntCommand())
print(intResult)

let stringResult = commandBus.dispatch(StringCommand())
print(stringResult)