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