Is it possible to save an enumeration template with an associated value in an array?

Let's say we have a simple enumeration with message types:

enum MessageType { case audio case photo case text } 

There is a Handler class that processes messages with only certain types:

 class Handler { let allowed: [MessageType] init(_ allowed: [MessageType]) { self.allowed = allowed } func canHandle(_ messageType: MessageType) -> Bool { return allowed.contains(messageType) } } 

Basic Usage Example:

 let handler = Handler([.audio, .photo]) print(handler.canHandle(.text)) // Prints false 

I want to update my MessageType and add a related value for some message types.

 class Audio {} enum MessageType { case audio(Audio) case photo case text } 

The problem is that I cannot store the enum pattern in the allowed array for future canHandle check:

 // error: '_' can only appear in a pattern or on the left side of an assignment let handler = Handler([.audio(_), .photo]) 

Can such a case be resolved in a โ€œcleanโ€ way?

  • It is not possible to modify MessageType because it is in a third-party library (for example, creating arguments is optional and passing nil )
  • Cannot initialize MessageType.audio(Audio) with fake Audio , as it may have a private initializer
  • I hope to avoid switch , case let or other hard-coded checks in canHandle

Any suggestions? Thanks

do androids dream of electric change

+5
source share
1 answer

If an enumeration instance with a default value (or garbage) doesn't really matter

 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) } } } 

Main use

 let handler = Handler([.audio(""), .photo]) print(handler.canHandle(.text)) // Prints false print(handler.canHandle(.audio("abc")) //Prints true 


The default values โ€‹โ€‹(or garbage) are unrealistic

This particular section is more specific in this context, but in the end you will have a breakdown of your listing in some way on Swift 4 .. This is my suggestion: Injection of the Factory Template inside Handler . This completely eliminates all your problems without touching the switch in the Handler or additional ones.

 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 } } } 

Main use

 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 

Perhaps you are asking: wait ... you just created another enumeration (also this is just an example, you can convert it to any of what you want in this protocol). Well, I say: the enum you use is from the library ... see the section of my notes. In addition, you can now use this Factory anywhere to break the type of library into something, including inside the Handler . You could easily extend the MessageTypeFactory protocol to convert your enumeration to the other types (hopefully the behavior) that you created, and basically just distance yourself from the type of library when you need to. Hope this helps clarify what I was aiming for! I donโ€™t even think you should store MessageType in your class. You must save your own type, which is some display version of MessageType , such as DisassembledType .

Hope this helps!


Notes

A few things:

  • I'm sorry that your soul belongs to the library, really.
  • Use an adapter template. Clean C ++ is one of many places where you can find out about it. Do not pollute your entire code base with one of their types! This is just a clue.
  • I know that you said you donโ€™t want to use the switch ... but you are working with enumerations ... At least it's in an enumeration!
  • Use your own types! (Did I say that?)
  • Use the adapter template! (Stop him.)
+1
source

Source: https://habr.com/ru/post/1276002/


All Articles