A practice app, part 1: the logic
This step and the next build a larger application, in the way step 5 described: the logic first, in classes that know nothing about windows, and then the views on top of them.
What the app does
The app trains the capitals of countries, with cards:
- The user adds cards: a country and its capital, such as Peru and Lima.
- The user trains: the app shows a country, the user types its capital, and the app says whether that was right and goes on to the next card. It counts the right and the wrong answers.
- The cards come in the order they were added, and after the last one the first one comes again.
A real trainer might shuffle the cards with Random (module 46). A fixed order keeps every run the same, which makes the app easy to check, and shuffling can be added later in one place: the logic.
Three classes
The logic has two jobs, so it gets two main classes. A CardBox stores the cards, each a small Card object with a country and its capital. A PracticeRound runs the training: whose turn it is, and the counts.
The diagram as text
- Card, a class
- private field
country: String - private field
capital: String - public constructor
Card(country: String, capital: String) - public method
getCountry(): String - public method
getCapital(): String
- private field
- CardBox, a class
- private field
cards: ArrayList<Card> - public constructor
CardBox() - public method
add(country: String, capital: String): boolean - public method
capitalOf(country: String): String - public method
countryAt(index: int): String - public method
size(): int
- private field
- PracticeRound, a class
- private field
box: CardBox - private field
next: int - private field
right: int - private field
wrong: int - public constructor
PracticeRound(box: CardBox) - public method
question(): String - public method
answer(text: String): boolean - public method
getRight(): int - public method
getWrong(): int
- private field
Connections:
- Each CardBox has any number of Card objects.
- Each PracticeRound has one CardBox object.
The window will use only some of these: the view for adding cards calls add and size, and the training view calls question, answer, the getters, and capitalOf for its feedback. Deciding what the logic offers before any window exists is the point of starting with it.
The card box
public class Main {
public static void main(String[] args) {
CardBox box = new CardBox();
System.out.println(box.add("Peru", "Lima"));
System.out.println(box.add("Kenya", " Nairobi "));
System.out.println(box.add("Peru", "Cusco"));
System.out.println(box.add(" ", "Oslo"));
System.out.println(box.size() + " cards, the first is " + box.countryAt(0));
System.out.println(box.capitalOf("Kenya") + " " + box.capitalOf("Chile"));
}
}import java.util.ArrayList;
public class CardBox {
private ArrayList<Card> cards;
public CardBox() {
this.cards = new ArrayList<>();
}
public boolean add(String country, String capital) {
String name = country.trim();
String city = capital.trim();
if (name.isEmpty() || city.isEmpty() || this.capitalOf(name) != null) {
return false;
}
this.cards.add(new Card(name, city));
return true;
}
public String capitalOf(String country) {
for (Card card : this.cards) {
if (card.getCountry().equals(country)) {
return card.getCapital();
}
}
return null;
}
public String countryAt(int index) {
return this.cards.get(index).getCountry();
}
public int size() {
return this.cards.size();
}
}public class Card {
private String country;
private String capital;
public Card(String country, String capital) {
this.country = country;
this.capital = capital;
}
public String getCountry() {
return this.country;
}
public String getCapital() {
return this.capital;
}
}true
true
false
false
2 cards, the first is Peru
Nairobi null- The box keeps its cards in one ArrayList of Card objects, so they stay in the order they were added, and
countryAtgives a card's country by its place in that order. A HashMap from country to capital would find a capital faster, but its order is its own (module 31), so the training would jump around. capitalOfwalks through the cards and returns the capital of the first card with that country, ornullwhen no card has it, asHashMap'sgetwould.adduses it to find out whether a country is in the box already.addrefuses a card with an empty country or capital, and a country that is in the box already, and returnsfalsefor them. The view will turn thatfalseinto a message, but the rule itself lives here.- The texts are trimmed before they're stored, so
" Nairobi "becomesNairobi.
The practice round
A PracticeRound gets the box in its constructor, the way step 5's views got the jar. It keeps next, the index of the card whose turn it is. It starts at 0, and each answer moves it on by one; after the last card it goes back to 0. Since the round asks the box each time, cards added during the training simply join it.