I've got code that looks like this:
class Base {
func launch(code1: Int, code2: Int) -> Bool { return false }
}
class A: Base {}
class B: Base {}
class C: Base {}
func trynext(obj: Base) -> Base? {
switch obj {
case is A: return B()
case is B: return C()
default: return nil
}
}
Basically, I've got a lot (like 20) of subclasses of a common base class and I need to go through them one by one. These subclasses represent parsers and I'm trying them one after another to discover which parser correctly parses some data.
If I fail on a parse, I call a function trynext
to return the "next parser" to try. You can imagine that this switch
statement can get unyieldly if the constructors take arguments (all subclasses take the same arguments), and the more subclasses there are, etc.
Is there any way I can streamline this code by putting the classes into some sort of array and loop through it somehow? The idea is to reduce the boilerplate so that I end up using a structure like [A, B, C]
that implies the subclasses to try and the order to try them in.
I would use a Protocol (say: "Parser") to define an interface that describes what the parser can do. E.g.: parse(data);
Different Implementations of this Protocol (A, B, C…) will have their own code to deal with the parsing.
The Parsing Controller (or Manager or whatever name you come up with), will store an Array of Parser
objects.
In a forEach loop, you can call each try Parser.parse(data); … and deal with either going to the next or aborting if the parsing was ok.
The particular implementations of your Parsers (A, B, C…) are irrelevant to the caller (as it should be). The ParsingController (where you have your switch right now), couldn't care less about what happens. It's only interested in success or failure to stop or try the next one respectively (if there's a next).
UPDATE: I have created a small Playground code you can paste and see what I mean.
UPDATE2: I have added an extension protocol so you can see how to so something akin to an abstract class to have a base/common set of functions/values.
import Swift
protocol Parser {
func parse(code1: Int, code2: Int) -> Bool
}
extension Parser {
var someCalculatedProperty: Int {
return 12345
}
func someCommonMethod() {
print("Some Common Method")
}
}
class A : Parser {
func parse(code1: Int, code2: Int) -> Bool { return false }
}
class B : Parser {
func parse(code1: Int, code2: Int) -> Bool { return false }
}
class C : Parser {
func parse(code1: Int, code2: Int) -> Bool { return true }
}
// Create 4 Parsers (two of the same type, just to demonstrate)
var parsers = [Parser](arrayLiteral: A(), A(), B(), C())
// Iterate the parsers until we get a success
for parser in parsers {
if parser.parse(0, code2: 1) {
print("Success")
// Just for fun, call common parser methods.
parser.someCommonMethod()
print(parser.someCalculatedProperty)
break
} else {
print("Fail")
}
}
Output should be:
Fail
Fail
Fail
Success
Some Common Method
12345
3 Failures (because A, A, B return false) and the the Success because of C that returns true. Then the common methods' output.