Poor Man's Console MVC
As MVC has gotten more muddled, it's important to remember that there should be a clear connection between controllers and concepts.
Join the DZone community and get the full member experience.
Join For FreeAfter two posts of pure theory about the MVC Pattern Language, I was looking to provide some practical examples. The technical part is easy – everybody already knows how to implement that in various ways, but I couldn’t figure out how to show the whole mental models part of it. In the end, I came up with what follows – an MVC “Pet Clinic” in the console!
As we learned in the previous posts, on the idea level, MVC is most concerned with understanding the user’s way of thinking. Therefore, we won’t jump straight into code here. Instead, we’ll visit a real pet clinic on the outskirts of your town and watch our user at work.
She Ain’t a Computer Lady
The clinic that hired you is actually a small office that consists of a few rooms, the most important being the visiting room. The old lady that runs the place has no computer at the moment and you keep wondering why does she want to pay so much money for dedicated software. After a while, you conclude that this is exactly the kind of person who needs a dedicated piece of software. If you tried to give her the Spring’s Pet Clinic and call it a day, she’d be totally lost in it. You need to create a habitable environment for her, as she’ll be learning both using the computer and your program at the same time.
Gathering Requirements
Instead of acting like an idiot and asking the old lady for the “requirements” directly, you sit quietly and watch her work for a few hours. This gives you a pretty good idea of her workflow.
She keeps track of all her visits inside a calendar. When somebody calls to schedule a visit, she asks about the person’s name, pet names and preferred visit time. Then, when both sides agree on the time of the visit, she notes it down in her calendar.
When the visit time comes, the old lady takes out pets’ files, which contain all important information about their health history. Then she takes care of the pet itself. Not much interesting stuff here. She makes the same “you’re so lovely” face every time and solves all kinds of problems – from a pet being actually sick to being moody and not wanting to play with its owner (sigh). After she finishes the “care-taking” stuff, she sits down and writes a short summary of the visit. The summary consists of two parts – course and recommendations. She always writes down two copies – one for the owner and one to put in the pet’s file.
Modeling the Domain
You tried talking to the woman about the veterinary domain but it seems that talking to her about abstract terms and relationships is as productive as talking with you about Malaysian poetry of the 19th century. Luckily, the concepts behind scheduling a visit seem easy enough to create the first prototype without creating an advanced domain model. You start off with something like this:
What’s in the Lady’s Head?
As we said before, simply creating a CRUD for visits, pets, and owners is not enough. We want better than this. Therefore, we have to look for things that will make the user instantly familiar with our software; something that improves his workflow instead of completely turning it around. In the case of our vet lady, these things would be the visit calendar and the pet files.
The physical calendar that the lady uses looks like a big notebook in which every two pages represent a single week. When a visit is scheduled, she notes things down using a specific format: hour goes first, then the owner’s name and the pets in the end.
The pet files are cardboard folders containing all of the summaries from the previous visits and occasionally some other medical documentation. The old lady keeps them in a desk’s locker, sorted alphabetically so that she can find the right one faster when the visit starts.
Implementing a Visit Calendar
The visit calendar will become a business object in our system. Since there will be quite a lot console printing and input parsing, we’ll separate it into the famous MVC triplet: model, view, and controller. This triplet should work together to give the lady a feeling that she’s working with her old calendar, just that the calendar is now computerized. Therefore, we’ll keep the weekly grouping of visits and allow her to switch the weeks like she’d be flipping pages in her old calendar. We’ll also print the visit information in a format similar to the one she used in her old calendar. I did some basic implementation, let’s take a look at it.
Controller
So far our controller recognizes three commands: “next” and “previous”, which change the calendar’s week, and “add”, which allows for adding a visit to the calendar:
public class VisitCalendarController implements Controller {
// field, c-tor
public boolean execute(String command) {
if ("next".equals(command)) {
visitCalendar.nextWeek();
return true;
}
if ("previous".equals(command)) {
visitCalendar.previousWeek();
return true;
}
if (command.startsWith("add")) {
parseAdd(command);
return true;
}
return false;
}
// parseAdd method
}
Model
The model is responsible for holding the information about the currently selected week and allows manipulating the underlying visits. By the means of changed() method, it lets the view know whenever something changes in the calendar:
public class VisitCalendar extends Model {
static final DayOfWeek[] OPEN_DAYS = {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY};
private Week currentWeek;
private Visits visits;
// c-tor
Week getCurrentWeek() {
return currentWeek;
}
void nextWeek() {
this.currentWeek = currentWeek.next();
changed();
}
void previousWeek() {
this.currentWeek = currentWeek.previous();
changed();
}
List<Visit> visitsOn(DayOfWeek day) {
return visits.on(currentWeek.get(day));
}
void addVisit(DayOfWeek dayOfWeek, LocalTime time, String ownerName, String[] petNames) {
// stuff
changed();
}
}
View
The view displays weekly visits in a format similar to the one already used by the vet lady and accepts user’s commands:
public class VisitCalendarView implements View {
// fields, c-tor
public void modelChanged() {
show();
}
public void show() {
show(visitCalendar.getCurrentWeek());
for (DayOfWeek day : VisitCalendar.OPEN_DAYS)
show(day);
askForCommand();
}
private void show(Week week) {
System.out.println(week.getStart() + " - " + week.getEnd());
}
private void show(DayOfWeek day) {
System.out.println(day + ":");
show(visitCalendar.visitsOn(day));
}
private void show(List<Visit> visitsOnDay) {
if (visitsOnDay.isEmpty()) {
System.out.println("No visits!");
} else {
visitsOnDay.forEach(this::show);
}
}
private void show(Visit visit) {
System.out.println(visit.getTime() + ": " + visit.getOwnerName());
System.out.println("Pets: " + visit.getPetNames());
}
private void askForCommand() {
try (Scanner scanner = new Scanner(System.in)) {
String command;
do {
command = scanner.nextLine();
} while (!controller.execute(command));
}
}
}
Conclusion and Next Steps
That’s everything I did in this prototype so far. The whole source code is available here. As you probably noticed, there’s no technical rocket science in there and not even any new concept at the first glance. I think the most important thing about this example is that the user is communicating directly with the business objects. She’s not talking to some generic VisitController
, which talks to some generic VisitService
. Instead, we’re exposing her to communication with an object she already knows – the VisitCalendar
.
In the next post, I’ll try to move our visit calendar to the web and we’ll see how the concept of business objects plays with “so-called” Web MVC frameworks like Spring MVC. If I have enough time (which is unlikely, but possible), I’ll try to add the second business object to the system – the pet files. Obviously, if someone from the readership wants to try their strengths in doing that, pull requests are welcome!
Published at DZone with permission of Grzegorz Ziemoński, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments