I'm currently following Java moocfi Helsinki course.
This is my current assignment :
In this exercise we are going to create a program that allows for searching for recipes based on their name, cooking time, or the name of an ingredient. The program should read the recipes from a file that the user provides. It might be a good idea to brush up on reading information from files (part 4) before beginning.
Each recipe consists of three or more rows in a recipe file. The first row is for the name of the recipe, the second the cooking time (an integer), and the third and possibly following rows list the ingredients used in the recipe. An empty row follows the last ingredient row. There can be many recipes in a single file. Below, an example file containing recipes is described.
- Reading and listing recipes: First create the functionality to read and list recipes. The user interface of the program is described below. You may assume that the user only enters files that exist. Below we assume that the example recipes given earlier in the exercise description are stored in the file recipes.txt
- Finding recipes by name: Make it possible to find recipes by their names. Finding by name is done with the command find name, after which the user is asked for the name that is used to search. The search should print all the recipes whose names contain the string given by the user.
- Searching for recipes by cooking time: Next, implement the possibility to find recipes based on their cooking time. This is done with the command find cooking time, after which the user is asked for the longest acceptable cooking time. The program should react by printing all the recipes whose cooking times don't exceed the cooking time given by the user (so equal or less time).
- Finding recipes based on their ingredients: Finally, add the functionality to search for recipes based on their ingredients. This is done by choosing the command find ingredient, after which the user is asked for a string. The program should then print all the recipes that contain the specified string. Notice that with this option the given string must match exactly the ingredient that is searched for (e.g. "ugar" will return different results than "sugar").
This is my solution. I already have a tiny background in Java, but I'm trying to improve at separating the program logic from the user interface. Any suggestions will be appreciated.
recipes.txt
Pancake dough
60
milk
egg
flour
salt
butter
Meatballs
20
ground meat
egg
breadcrumbs
Tofu rolls
30
tofu
rice
water
carrot
cucumber
avocado
wasabi
RecipeSearch.java
import java.util.Scanner;
public class RecipeSearch {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
RecipesCollection recipesCollection = new RecipesCollection();
UserInterface ui = new UserInterface(scanner, recipesCollection);
ui.start();
}
}
UserInterface.java
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
public class UserInterface {
private final static List<String> USAGE;
static {
final String[] list = new String[]{
"list - lists the recipes",
"stop - stops the program",
"find name - searches recipes by name",
"find cooking time - searches recipes by cooking time",
"find ingredient - searches recipes by ingredient"
};
USAGE = Collections.unmodifiableList(Arrays.asList(list));
}
private Scanner scanner;
private RecipesCollection recipesCollection;
public UserInterface(Scanner scanner, RecipesCollection recipesCollection) {
this.scanner = scanner;
this.recipesCollection = recipesCollection;
}
public void start() {
System.out.print("File to read:");
String fileName = scanner.nextLine();
recipesCollection.fillCollectionFromFile(fileName);
USAGE.forEach(System.out::println);
while (true) {
System.out.print("Enter command: ");
String command = scanner.nextLine();
if (command.equals("stop")) {
break;
} else if (command.equals("list")) {
this.recipesCollection.listRecipes();
} else if (command.equals("find name")) {
System.out.print("Searched word:");
String name = scanner.nextLine();
this.recipesCollection.findByName(name);
} else if (command.equals("find cooking time")) {
System.out.print("Max cooking time:");
int time = Integer.parseInt(scanner.nextLine());
this.recipesCollection.findByCookingTime(time);
} else if (command.equals("find ingredient")) {
System.out.print("Ingredient:");
String ingredient = scanner.nextLine();
this.recipesCollection.findByIngredient(ingredient);
}
}
}
}
Recipe.java
import java.util.List;
public class Recipe {
private final String name;
private final int preparationTime;
private final List<String> ingredients;
public Recipe(String name, int preparationTime, List<String> ingredients) {
this.name = name;
this.preparationTime = preparationTime;
this.ingredients = ingredients;
}
public String getName() {
return name;
}
public int getPreparationTime() {
return preparationTime;
}
public List<String> getIngredients() {
return ingredients;
}
@Override
public String toString() {
return name + ", cooking time: " + preparationTime;
}
}
RecipesCollection.java
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class RecipesCollection {
private List<Recipe> recipes;
public RecipesCollection() {
this.recipes = new ArrayList<>();
}
public void fillCollectionFromFile(String fileName) {
try (Scanner scanner = new Scanner(Paths.get(fileName))) {
while (scanner.hasNextLine()) {
String recipeName = scanner.nextLine();
int preparationTime = Integer.parseInt(scanner.nextLine());
ArrayList<String> ingredients = new ArrayList<>();
while (scanner.hasNextLine()) {
String ingredient = scanner.nextLine();
if (ingredient.isEmpty()) {
break;
}
ingredients.add(ingredient);
}
Recipe recipe = new Recipe(recipeName, preparationTime, ingredients);
this.recipes.add(recipe);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void listRecipes() {
System.out.println("Recipes:");
this.recipes.forEach(System.out::println);
}
public void findByName(String name) {
System.out.println("Recipes:");
ArrayList<Recipe> searchResult = new ArrayList<>();
for (Recipe recipe :
this.recipes) {
if (recipe.getName().contains(name)) {
searchResult.add(recipe);
}
}
searchResult.forEach(System.out::println);
}
public void findByCookingTime(int time) {
System.out.println("Recipes:");
ArrayList<Recipe> searchResult = new ArrayList<>();
for (Recipe recipe :
this.recipes) {
if (recipe.getPreparationTime() <= time) {
searchResult.add(recipe);
}
}
searchResult.forEach(System.out::println);
}
public void findByIngredient(String ingredient) {
System.out.println("Recipes:");
ArrayList<Recipe> searchResult = new ArrayList<>();
for (Recipe recipe :
this.recipes) {
if (recipe.getIngredients().contains(ingredient)) {
searchResult.add(recipe);
}
}
searchResult.forEach(System.out::println);
}
}