views:

83

answers:

2

I'm new to designing OO systems. I have a simple Flash Cards app where I'm having trouble figuring out the proper way to architect the system. The application has a simple GUI with a question, answer, and couple buttons. The questions and answers dataset are stored in a Derby embedded database.

Quick Setup:
Database Class - Handles the connect,disconnect, and returns an ArrayList based on a selected filter (currently called by a CardSet object) (the DB class is set up as static)
CardSet Class- Holds the ArrayList being used currently, holds the current Card
Card Class - holds the data for the flash card (question and answer, couple other things)
App Class - Creates the GUI and handles the action events

So here is my question: I want to separate the GUI and the application logic. I am thinking it may be a good case for MVC, but I'm not sure how to really separate it all(never used it) . Does a controller class get created in the main which then launches the GUI and then creates the other classes (in my case, the CardSet). What about access? Do certain things need to be static?

Another question- For handling the GUI events, do you just set it up to call a generic method in the controller class? For instance, the "Next Card" button is clicked, should it just call something like controller.nextCardAction()? Should I try to just use the Observer pattern to let the GUI pull the data?

Sorry for the beginner questions, but this is my first go around at a Java app. Any help would be great. Good links are welcome as well. I have the Head First Design Patterns book, but it just doesn't have enough real examples for me to fully grasp it for my app.

+1  A: 

Look into the listener pattern.

Rewrite a part of your GUI to listen to the "current flashcard". The code for the GUI should look something like this:

public interface ModelListener {
   public void modelChanged();
}

public class FlashCardView implements ModelListener {

   private FlashCard model;

   public FlashCardView(FlashCard card) {
     setModel(card);
   }

   public void setModel(FlashCard card) {
     if (model != null) {
       model.removeListener(this);
     }
     model = card;
     model.addListener(this);
   }

   public void modelChanged() {
     (read out model values and update the screen displayed values)
   }

}

public interface Model {
    public void addListener(ModelListener listener);
    public void removeListener(ModelListener listener);
}

public class FlashCard() {

   private String answer;

   private String question;

   private Vector<ModelListener> listeners;

   public FlashCard(String question, String answer) {
     this.question = question;
     this.answer = answer;
     this.listeners = new Vector<ModelListener>();
   }

   public void setAnswer(String newAnswer) {
     this.answer = newAnswer;
   }

   public void setQuestion(String newQuestion) {
     this.question = newQuestion
   }

   public void addListener(ModelListener listener) {
     listeners.add(listener);
   }

   public void removeListener(ModelListener listener) {
     listeners.remove(listener);
   }

   private void notifyListeners() {
     for (ModelListener listener : listeners) {
        listener.modelChanged();
     }
   }

}

Put all of the actions your buttons perform and the choice of which "views" to display at any given time into a "Controller" class. Basically, it should be calling the setModel(...) methods, and it should add and remove the "view" classes from the current displayed window.

While this might seem like a bit of code to display a simple flashcard, remember that a lot of your model will be more sophisticated than a flashcard. You will probably need classes to represent tests, topics, etc. in the near future.

Edwin Buck
Thanks for the detailed response. Where would you read the DB stuff? Controller class? Would you store your set of flashcards there using this pattern?
Awaken
The Controller would read from the storage facilities creating new model classes as needed. Where you store your flash cards is your business, but odds are it will either be on disk or in a database. Since storage isn't the same a simulating the model, a different pattern would probably be best. As for the the code for the model, well, that really depends on what you write, I can't provide your program for you with any accuracy considering how loose the requirements are, but I'm glad to show you how a pattern can be applied to one part of it.
Edwin Buck
+1  A: 

Here's a very simple example and discussion that may be helpful.

Where would you read the DB stuff?

I'd expect the model to maintain a reference to the current CardSet, initializing it to some default on construction and refilling it whenever the controller says the user wants a new set. Only the CardSet knows where Cards come from or how to get a new set. In response to user action, the view asks the model for the next or previous card, and updates itself when it hears back from the model to which it is listening.

Don't confuse the controller with controls: both the view and the controller may manage controls such as buttons. In the example cited, the controller has a reset button, while the view has a panel of game buttons. In your application, the controller might initiate changing sets, while the view has controls to move among the cards in a set.

For reference, the solid lines in the MVC diagram are method invocations and the dotted lines are callbacks to the listener. In the example cited, the Observable and Observer classes provide the update() callback, but the EventListenerList mechanism is also common.

trashgod
@Awaken: I've updated my answer in response to your comment.
trashgod