Skip to content

Commit 3ec59e8

Browse files
jagdish-15kahgoh
andauthored
Add method based if approach for Bob (#2861)
Co-authored-by: Kah Goh <[email protected]>
1 parent 3b72eac commit 3ec59e8

File tree

6 files changed

+191
-25
lines changed

6 files changed

+191
-25
lines changed

exercises/practice/bob/.approaches/config.json

+19-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,30 @@
22
"introduction": {
33
"authors": [
44
"bobahop"
5+
],
6+
"contributors": [
7+
"jagdish-15",
8+
"kahgoh"
59
]
610
},
711
"approaches": [
12+
{
13+
"uuid": "6ca5c7c0-f8f1-49b2-b137-951fa39f89eb",
14+
"slug": "method-based-if-statements",
15+
"title": "method-based if statements",
16+
"blurb": "Use if statements to return the answer with the help of methods.",
17+
"authors": [
18+
"jagdish-15"
19+
],
20+
"contributors": [
21+
"BenjaminGale",
22+
"kahgoh"
23+
]
24+
},
825
{
926
"uuid": "323eb230-7f27-4301-88ea-19c39d3eb5b6",
10-
"slug": "if-statements",
11-
"title": "if statements",
27+
"slug": "variable-based-if-statements",
28+
"title": "variable-based if statements",
1229
"blurb": "Use if statements to return the answer.",
1330
"authors": [
1431
"bobahop"

exercises/practice/bob/.approaches/introduction.md

+64-22
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,65 @@
11
# Introduction
22

3-
There are various idiomatic approaches to solve Bob.
4-
A basic approach can use a series of `if` statements to test the conditions.
5-
An array can contain answers from which the right response is selected by an index calculated from scores given to the conditions.
3+
In this exercise, we’re working on a program to determine Bob’s responses based on the tone and style of given messages.
4+
Bob responds differently depending on whether a message is a question, a shout, both, or silence.
5+
Various approaches can be used to implement this logic efficiently and cleanly, ensuring the code remains readable and easy to maintain.
66

77
## General guidance
88

9-
Regardless of the approach used, some things you could look out for include
9+
When implementing your solution, consider the following tips to keep your code optimized and idiomatic:
1010

11-
- If the input is trimmed, [`trim()`][trim] only once.
11+
- **Trim the Input Once**: Use [`trim()`][trim] only once at the start to remove any unnecessary whitespace.
12+
- **Use Built-in Methods**: For checking if a message is a question, prefer [`endsWith("?")`][endswith] instead of manually checking the last character.
13+
- **Single Determinations**: Use variables for `questioning` and `shouting` rather than calling these checks multiple times to improve efficiency.
14+
- **DRY Code**: Avoid duplicating code by combining the logic for determining a shout and a question when handling shouted questions. Following the [DRY][dry] principle helps maintain clear and maintainable code.
15+
- **Return Statements**: An early return in an `if` statement eliminates the need for additional `else` blocks, making the code more readable.
16+
- **Curly Braces**: While optional for single-line statements, some teams may require them for readability and consistency.
1217

13-
- Use the [`endsWith()`][endswith] `String` method instead of checking the last character by index for `?`.
18+
## Approach: method-based `if` statements
1419

15-
- Don't copy/paste the logic for determining a shout and for determining a question into determining a shouted question.
16-
Combine the two determinations instead of copying them.
17-
Not duplicating the code will keep the code [DRY][dry].
20+
```java
21+
class Bob {
22+
String hey(String input) {
23+
var inputTrimmed = input.trim();
24+
25+
if (isSilent(inputTrimmed)) {
26+
return "Fine. Be that way!";
27+
}
28+
if (isShouting(inputTrimmed) && isQuestioning(inputTrimmed)) {
29+
return "Calm down, I know what I'm doing!";
30+
}
31+
if (isShouting(inputTrimmed)) {
32+
return "Whoa, chill out!";
33+
}
34+
if (isQuestioning(inputTrimmed)) {
35+
return "Sure.";
36+
}
37+
38+
return "Whatever.";
39+
}
1840

19-
- Perhaps consider making `questioning` and `shouting` values set once instead of functions that are possibly called twice.
41+
private boolean isShouting(String input) {
42+
return input.chars()
43+
.anyMatch(Character::isLetter) &&
44+
input.chars()
45+
.filter(Character::isLetter)
46+
.allMatch(Character::isUpperCase);
47+
}
2048

21-
- If an `if` statement can return, then an `else if` or `else` is not needed.
22-
Execution will either return or will continue to the next statement anyway.
49+
private boolean isQuestioning(String input) {
50+
return input.endsWith("?");
51+
}
2352

24-
- If the body of an `if` statement is only one line, curly braces aren't needed.
25-
Some teams may still require them in their style guidelines, though.
53+
private boolean isSilent(String input) {
54+
return input.length() == 0;
55+
}
56+
}
57+
```
58+
59+
This approach defines helper methods for each type of message—silent, shouting, and questioning—to keep each condition clean and easily testable.
60+
For more details, refer to the [method-based `if` Statements Approach][approach-method-if].
2661

27-
## Approach: `if` statements
62+
## Approach: variable-based `if` statements
2863

2964
```java
3065
import java.util.function.Predicate;
@@ -56,7 +91,8 @@ class Bob {
5691
}
5792
```
5893

59-
For more information, check the [`if` statements approach][approach-if].
94+
This approach uses variables to avoid rechecking whether Bob is silent, shouting or questioning.
95+
For more details, refer to the [variable-based `if` Statements Approach][approach-variable-if].
6096

6197
## Approach: answer array
6298

@@ -86,16 +122,22 @@ class Bob {
86122
}
87123
```
88124

89-
For more information, check the [Answer array approach][approach-answer-array].
125+
This approach uses an array of answers and calculates the appropriate index based on flags for shouting and questioning.
126+
For more details, refer to the [Answer Array Approach][approach-answer-array].
127+
128+
## Which Approach to Use?
129+
130+
The choice between the **Method-Based `if` Statements Approach**, **Variable-Based `if` Statements Approach**, and the **Answer Array Approach** depends on readability, maintainability, and efficiency:
90131

91-
## Which approach to use?
132+
- **Method-Based `if` Statements Approach**: This is clear and easy to follow but checks conditions multiple times, potentially affecting performance. Storing results in variables like `questioning` and `shouting` can improve efficiency but may reduce clarity slightly.
133+
- **Variable-Based `if` Statements Approach**: This approach can be more efficient by avoiding redundant checks, but its nested structure can reduce readability and maintainability.
134+
- **Answer Array Approach**: Efficient and compact, this method uses an array of responses based on flags for questioning and shouting. However, it may be less intuitive and harder to modify if more responses are needed.
92135

93-
Since benchmarking with the [Java Microbenchmark Harness][jmh] is currently outside the scope of this document,
94-
the choice between `if` statements and answers array can be made by perceived readability.
136+
Each approach offers a balance between readability and performance, with trade-offs in flexibility and clarity.
95137

96138
[trim]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim()
97139
[endswith]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#endsWith(java.lang.String)
98140
[dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
99-
[approach-if]: https://exercism.org/tracks/java/exercises/bob/approaches/if-statements
141+
[approach-method-if]: https://exercism.org/tracks/java/exercises/bob/approaches/method-based-if-statements
142+
[approach-variable-if]: https://exercism.org/tracks/java/exercises/bob/approaches/variable-based-if-statements
100143
[approach-answer-array]: https://exercism.org/tracks/java/exercises/bob/approaches/answer-array
101-
[jmh]: https://github.com/openjdk/jmh
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Method-Based `if` statements
2+
3+
```java
4+
class Bob {
5+
String hey(String input) {
6+
var inputTrimmed = input.trim();
7+
8+
if (isSilent(inputTrimmed)) {
9+
return "Fine. Be that way!";
10+
}
11+
if (isShouting(inputTrimmed) && isQuestioning(inputTrimmed)) {
12+
return "Calm down, I know what I'm doing!";
13+
}
14+
if (isShouting(inputTrimmed)) {
15+
return "Whoa, chill out!";
16+
}
17+
if (isQuestioning(inputTrimmed)) {
18+
return "Sure.";
19+
}
20+
21+
return "Whatever.";
22+
}
23+
24+
private boolean isShouting(String input) {
25+
return input.chars()
26+
.anyMatch(Character::isLetter) &&
27+
input.chars()
28+
.filter(Character::isLetter)
29+
.allMatch(Character::isUpperCase);
30+
}
31+
32+
private boolean isQuestioning(String input) {
33+
return input.endsWith("?");
34+
}
35+
36+
private boolean isSilent(String input) {
37+
return input.length() == 0;
38+
}
39+
}
40+
```
41+
42+
In this approach, the different conditions for Bob’s responses are separated into dedicated private methods within the `Bob` class.
43+
This method-based approach improves readability and modularity by organizing each condition check into its own method, making the main response method easier to understand and maintain.
44+
45+
## Explanation
46+
47+
This approach simplifies the main method `hey` by breaking down each response condition into helper methods:
48+
49+
### Trimming the Input
50+
51+
The `input` is trimmed using the `String` [`trim()`][trim] method to remove any leading or trailing whitespace.
52+
This helps to accurately detect if the input is empty and should prompt a `"Fine. Be that way!"` response.
53+
54+
~~~~exercism/caution
55+
Note that a `null` `string` would be different from a `String` of all whitespace.
56+
A `null` `String` would throw a `NullPointerException` if `trim()` were applied to it.
57+
~~~~
58+
59+
### Delegating to Helper Methods
60+
61+
Each condition is evaluated using the following helper methods:
62+
63+
1. **`isSilent`**: Checks if the trimmed input has no characters.
64+
2. **`isShouting`**: Checks if the input is all uppercase and contains at least one alphabetic character, indicating shouting.
65+
3. **`isQuestioning`**: Verifies if the trimmed input ends with a question mark.
66+
67+
This modular approach keeps each condition encapsulated, enhancing code clarity.
68+
69+
### Order of Checks
70+
71+
The order of checks within `hey` is important:
72+
73+
1. Silence is evaluated first, as it requires an immediate response.
74+
2. Shouted questions take precedence over individual checks for shouting and questioning.
75+
3. Shouting comes next, requiring its response if not combined with a question.
76+
4. Questioning (a non-shouted question) is checked afterward.
77+
78+
This ordering ensures that Bob’s response matches the expected behavior without redundancy.
79+
80+
## Shortening
81+
82+
When the body of an `if` statement is a single line, both the test expression and the body _could_ be put on the same line, like so:
83+
84+
```java
85+
if (isSilent(inputTrimmed)) return "Fine. Be that way!";
86+
```
87+
88+
or the body _could_ be put on a separate line without curly braces:
89+
90+
```java
91+
if (isSilent(inputTrimmed))
92+
return "Fine. Be that way!";
93+
```
94+
95+
However, the [Java Coding Conventions][coding-conventions] advise always using curly braces for `if` statements, which helps to avoid errors.
96+
Your team may choose to overrule them at its own risk.
97+
98+
[trim]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim()
99+
[coding-conventions]: https://www.oracle.com/java/technologies/javase/codeconventions-statements.html#449
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
if (isSilent(inputTrimmed))
2+
return "Fine. Be that way!";
3+
if (isShouting(inputTrimmed) && isQuestioning(inputTrimmed))
4+
return "Calm down, I know what I'm doing!";
5+
if (isShouting(inputTrimmed))
6+
return "Whoa, chill out!";
7+
if (isQuestioning(inputTrimmed))
8+
return "Sure.";

exercises/practice/bob/.approaches/if-statements/content.md renamed to exercises/practice/bob/.approaches/variable-based-if-statements/content.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# `if` statements
1+
# Variable-Based `if` statements
22

33
```java
44
import java.util.function.Predicate;

0 commit comments

Comments
 (0)