patternswiftMinor
Switch statement for adding/removing operands to the text part of a label
Viewed 0 times
theremovingstatementtextpartaddingforoperandslabelswitch
Problem
I have a switch statement with five cases, and four of them are really similar to the others. How could I properly refactor this code to eliminate the duplication of code?
```
func appendOperand(operand: Operand) {
let displayedString = amountLabel.text!
if displayedString.last != decimalSeparator {
switch operand {
case Operand.Div:
if division {
dropLastChar()
} else {
if multiplication || subtraction || addition {
dropLastChar()
}
appendOperand(buttonDivision, operand: &division, operandName: "/")
}
case Operand.Mult:
if multiplication {
dropLastChar()
} else {
if division || subtraction || addition {
dropLastChar()
}
appendOperand(buttonMultiplication, operand: &multiplication, operandName: "x")
}
case Operand.Sub:
if subtraction {
dropLastChar()
} else {
if division || multiplication || addition {
dropLastChar()
}
appendOperand(buttonSubtraction, operand: &subtraction, operandName: "-")
}
case Operand.Add:
if addition {
dropLastChar()
} else {
if division || multiplication || subtraction {
dropLastChar()
}
appendOperand(buttonAddition, operand: &addition, operandName: "+")
}
default:
break
}
}
}
func appendOperand(button: UIButton, inout operand: Bool, operandName: String) {
setAllOperatorsToFalse()
operand = true
wasDecimalAmount = isDecimalAmount
isDecimalAmount = false
setDisplayWith(operandName)
}
func dropLastChar() {
isDecimalAmount = wasDecimalAmount
setAllOperatorsToFalse()
```
func appendOperand(operand: Operand) {
let displayedString = amountLabel.text!
if displayedString.last != decimalSeparator {
switch operand {
case Operand.Div:
if division {
dropLastChar()
} else {
if multiplication || subtraction || addition {
dropLastChar()
}
appendOperand(buttonDivision, operand: &division, operandName: "/")
}
case Operand.Mult:
if multiplication {
dropLastChar()
} else {
if division || subtraction || addition {
dropLastChar()
}
appendOperand(buttonMultiplication, operand: &multiplication, operandName: "x")
}
case Operand.Sub:
if subtraction {
dropLastChar()
} else {
if division || multiplication || addition {
dropLastChar()
}
appendOperand(buttonSubtraction, operand: &subtraction, operandName: "-")
}
case Operand.Add:
if addition {
dropLastChar()
} else {
if division || multiplication || subtraction {
dropLastChar()
}
appendOperand(buttonAddition, operand: &addition, operandName: "+")
}
default:
break
}
}
}
func appendOperand(button: UIButton, inout operand: Bool, operandName: String) {
setAllOperatorsToFalse()
operand = true
wasDecimalAmount = isDecimalAmount
isDecimalAmount = false
setDisplayWith(operandName)
}
func dropLastChar() {
isDecimalAmount = wasDecimalAmount
setAllOperatorsToFalse()
Solution
So, as a start, I'd take my enum, which you've stuck at the bottom, and move it to the top. It's great to use custom types, but sticking it at the bottom of the file does a disservice to readers. And the fact that it has been placed at the bottom makes me think that the author may have undervalued this custom type (and judging by the code, I'd say the enum certainly appears undervalued).
So:
Next, what are we gaining by abbreviating the operand types? Not a whole lot. We only have to fully type it out once, and the rest of the time it will autocomplete for us, right? Right. By fully typing out the name the first time, we're going to increase the readability throughout everywhere that uses the enum. And writing readable code is important.
So:
Finally, look at what we're doing. We call our
So:
Applying these three points gives us the following enum at the top of the file:
Now, we take a close inspection of the
There are more issues that can and should be addressed, but getting the enum right is so fundamental to this code that we need to take a breather after fixing that up, see what we can do after fixing that up, and reassess where we're at before we start making more changes.
So:
- Move the enum to the top so that future readers can start there.
Next, what are we gaining by abbreviating the operand types? Not a whole lot. We only have to fully type it out once, and the rest of the time it will autocomplete for us, right? Right. By fully typing out the name the first time, we're going to increase the readability throughout everywhere that uses the enum. And writing readable code is important.
So:
- Move the enum to the top so that future readers can start there.
- Don't abbreviate.
Finally, look at what we're doing. We call our
appendOperand and pass in one of our Operand enum values, and that does some work to eventually call an overloaded appendOperand method that takes a string. A string which we're magically associating with the operand, and only doing so in this very weird way. But why? Swift enums can have a backing value associated with them (and there's no performance hit either for storing them or for passing them around... they still perform the same). We can access that backing value using the rawValue property of enums.So:
- Move the enum to the top so that future readers can start there.
- Don't abbreviate.
- Use a backing value rather than magically associated strings.
Applying these three points gives us the following enum at the top of the file:
enum Operand: String {
case Multiply = "x"
case Divide = "/"
case Add = "+"
case Subtract = "-"
case Evaluate = "="
}Now, we take a close inspection of the
appendOperand method, and I notice a few oddities...- We take a
UIButtonargument, but we don't use it.
- We take an
inoutargument and returnvoid(hint: don't take the argument and just return a value).
- Now that we've fixed our enum, we can take the enum as an argument rather than a
String.
There are more issues that can and should be addressed, but getting the enum right is so fundamental to this code that we need to take a breather after fixing that up, see what we can do after fixing that up, and reassess where we're at before we start making more changes.
Code Snippets
enum Operand: String {
case Multiply = "x"
case Divide = "/"
case Add = "+"
case Subtract = "-"
case Evaluate = "="
}Context
StackExchange Code Review Q#100441, answer score: 2
Revisions (0)
No revisions yet.