Skip to content

Commit a58600a

Browse files
committed
Adding approach for Bob
1 parent 3369915 commit a58600a

File tree

3 files changed

+160
-22
lines changed

3 files changed

+160
-22
lines changed

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,24 @@
22
"introduction": {
33
"authors": [
44
"bobahop"
5+
],
6+
"contributors": [
7+
"jagdish-15"
58
]
69
},
710
"approaches": [
11+
{
12+
"uuid": "",
13+
"slug": "function-based",
14+
"title": "Function based",
15+
"blurb": "Uses boolean functions to check conditions",
16+
"authors": [
17+
"jagdish-15"
18+
],
19+
"contributors": [
20+
"BenjaminGale"
21+
]
22+
},
823
{
924
"uuid": "323eb230-7f27-4301-88ea-19c39d3eb5b6",
1025
"slug": "if-statements",

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

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,58 @@
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. Bob responds differently depending on whether a message is a question, a shout, both, or silence. Various approaches can be used to implement this logic efficiently and cleanly, ensuring the code remains readable and easy to maintain.
64

7-
## General guidance
5+
## General Guidance
86

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

11-
- If the input is trimmed, [`trim()`][trim] only once.
9+
- **Trim the Input Once**: Use [`trim()`][trim] only once at the start to remove any unnecessary whitespace.
10+
- **Use Built-in Methods**: For checking if a message is a question, prefer [`endsWith("?")`][endswith] instead of manually checking the last character.
11+
- **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.
12+
- **Single Determinations**: Use variables for `questioning` and `shouting` rather than calling these checks multiple times to improve efficiency.
13+
- **Return Statements**: An early return in an `if` statement eliminates the need for additional `else` blocks, making the code more readable.
14+
- **Curly Braces**: While optional for single-line statements, some teams may require them for readability and consistency.
1215

13-
- Use the [`endsWith()`][endswith] `String` method instead of checking the last character by index for `?`.
16+
## Approach: Method-Based
1417

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].
18+
```java
19+
class Bob {
20+
String hey(String input) {
21+
var inputTrimmed = input.trim();
22+
23+
if (isSilent(inputTrimmed))
24+
return "Fine. Be that way!";
25+
if (isYelling(inputTrimmed) && isAsking(inputTrimmed))
26+
return "Calm down, I know what I'm doing!";
27+
if (isYelling(inputTrimmed))
28+
return "Whoa, chill out!";
29+
if (isAsking(inputTrimmed))
30+
return "Sure.";
31+
32+
return "Whatever.";
33+
}
34+
35+
private boolean isYelling(String input) {
36+
return input.chars()
37+
.anyMatch(Character::isLetter) &&
38+
input.chars()
39+
.filter(Character::isLetter)
40+
.allMatch(Character::isUpperCase);
41+
}
1842

19-
- Perhaps consider making `questioning` and `shouting` values set once instead of functions that are possibly called twice.
43+
private boolean isAsking(String input) {
44+
return input.endsWith("?");
45+
}
2046

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.
47+
private boolean isSilent(String input) {
48+
return input.length() == 0;
49+
}
50+
}
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+
This approach defines helper methods for each type of message—silent, yelling, and asking—to keep each condition clean and easily testable. For more details, refer to the [Method-Based Approach][approach-method-based].
2654

27-
## Approach: `if` statements
55+
## Approach: `if` Statements
2856

2957
```java
3058
import java.util.function.Predicate;
@@ -56,9 +84,9 @@ class Bob {
5684
}
5785
```
5886

59-
For more information, check the [`if` statements approach][approach-if].
87+
This approach utilizes nested `if` statements and a predicate for determining if a message is a shout. For more details, refer to the [`if` Statements Approach][approach-if].
6088

61-
## Approach: answer array
89+
## Approach: Answer Array
6290

6391
```java
6492
import java.util.function.Predicate;
@@ -86,16 +114,22 @@ class Bob {
86114
}
87115
```
88116

89-
For more information, check the [Answer array approach][approach-answer-array].
117+
This approach uses an array of answers and calculates the appropriate index based on flags for shouting and questioning. For more details, refer to the [Answer Array Approach][approach-answer-array].
118+
119+
## Which Approach to Use?
120+
121+
Choosing between the method-based approach, `if` statements, and answer array approach can come down to readability and maintainability. Each has its advantages:
90122

91-
## Which approach to use?
123+
- **Method-Based**: Clear and modular, great for readability.
124+
- **`if` Statements**: Compact and straightforward, suited for smaller projects.
125+
- **Answer Array**: Minimizes condition checks by using indices, efficient for a variety of responses.
92126

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.
127+
Experiment with these approaches to find the balance between readability and performance that best suits your needs.
95128

96129
[trim]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim()
97130
[endswith]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#endsWith(java.lang.String)
98131
[dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
132+
[approach-method-based]: https://exercism.org/tracks/java/exercises/bob/approaches/method-based
99133
[approach-if]: https://exercism.org/tracks/java/exercises/bob/approaches/if-statements
100134
[approach-answer-array]: https://exercism.org/tracks/java/exercises/bob/approaches/answer-array
101135
[jmh]: https://github.com/openjdk/jmh
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Method-Based Approach
2+
3+
In this approach, the different conditions for Bob’s responses are separated into dedicated private methods within the `Bob` class. 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.
4+
5+
The main `hey` method determines Bob’s response by delegating each condition to a helper method (`isSilent`, `isYelling`, and `isAsking`), each encapsulating specific logic.
6+
7+
## Explanation
8+
9+
This approach simplifies the main method `hey` by breaking down each response condition into helper methods:
10+
11+
1. **Trimming the Input**:
12+
The `input` is trimmed using the `String` [`trim()`][trim] method to remove any leading or trailing whitespace. This helps to accurately detect if the input is empty and should prompt a `"Fine. Be that way!"` response.
13+
14+
2. **Delegating to Helper Methods**:
15+
Each condition is evaluated using the following helper methods:
16+
17+
- **`isSilent`**: Checks if the trimmed input has no characters.
18+
- **`isYelling`**: Checks if the input is all uppercase and contains at least one alphabetic character, indicating shouting.
19+
- **`isAsking`**: Verifies if the trimmed input ends with a question mark.
20+
21+
This modular approach keeps each condition encapsulated, enhancing code clarity.
22+
23+
3. **Order of Checks**:
24+
The order of checks within `hey` is important:
25+
- Silence is evaluated first, as it requires an immediate response.
26+
- Shouted questions take precedence over individual checks for yelling and asking.
27+
- Yelling comes next, requiring its response if not combined with a question.
28+
- Asking (a non-shouted question) is checked afterward.
29+
30+
This ordering ensures that Bob’s response matches the expected behavior without redundancy.
31+
32+
## Code structure
33+
34+
```java
35+
class Bob {
36+
String hey(String input) {
37+
var inputTrimmed = input.trim();
38+
39+
if (isSilent(inputTrimmed))
40+
return "Fine. Be that way!";
41+
if (isYelling(inputTrimmed) && isAsking(inputTrimmed))
42+
return "Calm down, I know what I'm doing!";
43+
if (isYelling(inputTrimmed))
44+
return "Whoa, chill out!";
45+
if (isAsking(inputTrimmed))
46+
return "Sure.";
47+
48+
return "Whatever.";
49+
}
50+
51+
private boolean isYelling(String input) {
52+
return input.chars()
53+
.anyMatch(Character::isLetter) &&
54+
input.chars()
55+
.filter(Character::isLetter)
56+
.allMatch(Character::isUpperCase);
57+
}
58+
59+
private boolean isAsking(String input) {
60+
return input.endsWith("?");
61+
}
62+
63+
private boolean isSilent(String input) {
64+
return input.length() == 0;
65+
}
66+
}
67+
```
68+
69+
## Advantages of the Method-Based Approach
70+
71+
- **Readability**: Each method is clearly responsible for a specific condition, making the main response logic easy to follow.
72+
- **Maintainability**: Changes to a condition can be confined to its method, minimizing impacts on the rest of the code.
73+
- **Code Reusability**: Helper methods can be reused or adapted easily if new conditions are added in the future.
74+
75+
## Considerations
76+
77+
- **Efficiency**: While this approach introduces multiple method calls, it enhances readability significantly, which is often more valuable in non-performance-critical applications.
78+
- **Error Prevention**: This approach avoids redundant code, reducing the risk of maintenance errors.
79+
80+
## Shortening Condition Checks
81+
82+
If each `if` statement body is only a single line, braces can be omitted, or the test expression and result could be placed on a single line. However, [Java Coding Conventions][coding-conventions] recommend always using curly braces for error prevention and easier future modifications.
83+
84+
### Alternative: Inline Helper Methods
85+
86+
For smaller projects, consider implementing helper methods inline or as lambdas, though this might reduce readability.
87+
88+
[trim]: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#trim()
89+
[coding-conventions]: https://www.oracle.com/java/technologies/javase/codeconventions-statements.html#449

0 commit comments

Comments
 (0)