假设我们有一个简单的带有消息类型的枚举:
enum MessageType {
case audio
case photo
case text
}
有
Handler
类,仅处理特定类型的消息:class Handler {
let allowed: [MessageType]
init(_ allowed: [MessageType]) { self.allowed = allowed }
func canHandle(_ messageType: MessageType) -> Bool {
return allowed.contains(messageType)
}
}
基本用法示例:
let handler = Handler([.audio, .photo])
print(handler.canHandle(.text)) // Prints false
我想升级
MessageType
并为某些消息类型添加关联的值。class Audio {}
enum MessageType {
case audio(Audio)
case photo
case text
}
问题是我无法将枚举的模式存储在
allowed
数组中,以便以后在canHandle
中进行检查:// error: '_' can only appear in a pattern or on the left side of an assignment
let handler = Handler([.audio(_), .photo])
是否有可能以“干净”的方式解决这种情况?
MessageType
,因为它在第三方库中(例如,使参数成为可选参数并传递nil
)MessageType.audio(Audio)
初始化Audio
,因为它可能具有私有(private)初始化程序switch
case let
,canHandle
或其他硬编码检查有什么建议么?谢谢
最佳答案
如果用默认(或无用值)实例化枚举并不重要
enum MessageType {
case audio(String)
case photo
case text
}
protocol SneakyEquatableMessage {
func equals(message: MessageType) -> Bool
}
extension MessageType: SneakyEquatableMessage {
func equals(message: MessageType) -> Bool {
switch (self, message) {
case (.audio(_), .audio(_)),
(.photo, .photo),
(.text, .text):
return true
default:
return false
}
}
}
class Handler {
let allowed: [MessageType]
init(_ allowed: [MessageType]) { self.allowed = allowed }
func canHandle(_ messageType: MessageType) -> Bool {
return allowed.contains { $0.equals(message: messageType) }
}
}
基本用法
let handler = Handler([.audio(""), .photo])
print(handler.canHandle(.text)) // Prints false
print(handler.canHandle(.audio("abc")) //Prints true
默认(或垃圾)值不现实
这个特定的部分在这种情况下更加具体,但是从Swift 4开始,最终将使您的枚举崩溃。所以这是我的建议:
Handler
内的工厂模式的依赖注入(inject)。这样就可以非常干净地解决您的所有问题,而无需触摸Handler或Optional中的开关。enum DisassembledMessage {
case audio
case photo
case text
}
protocol MessageTypeFactory {
func disassemble(message: MessageType) -> DisassembledMessage
func disassemble(messages: [MessageType]) -> [DisassembledMessage]
}
class Handler {
let allowed: [MessageType]
let factory: MessageTypeFactory
init(allowed: [MessageType], with factory: MessageTypeFactory) {
self.allowed = allowed
self.factory = factory
}
func canHandle(_ messageType: DisassembledMessage) -> Bool {
return factory
.disassemble(messages: allowed)
.contains { $0 == messageType }
}
}
基本用法
let audioValue: Audio = //...
let audioMessage = MessageType.audio(audioValue)
let factory: MessageTypeFactory = //...
let handler = Handler(allowed: [audioMessage, .photo], with: factory)
print(handler.canHandle(.text)) // Prints false
print(handler.canHandle(factory.disassemble(message: audioMessage))) //Prints true
您可能会问:等一下...您刚刚创建了另一个枚举(这只是一个示例,您可以将其转换为该协议(protocol)中想要的任何名称)。好吧,我说:您使用的枚举来自库...请参阅我的注释部分。而且,您现在可以在需要将库类型分解为某种类型的任何地方使用该工厂,包括
Handler
内部。您可以轻松地扩展协议(protocol)MessageTypeFactory
,以将您的枚举转换为您创建的其他类型(希望是行为),并且基本上只是在需要时与库类型保持距离。我希望这有助于弄清我的意思!我什至不认为您应该在类中存储MessageType
。您应该存储自己的类型,这是MessageType
的某种映射版本,例如DisassembledType
。我希望这有帮助!
注释
一些东西:
可以了解它。不要使用以下任何一种方式污染您的整个代码库
他们的类型!这只是一个提示。
关于swift - 是否可以将带有关联值的枚举模式存储在数组中?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49408946/