Sunday, March 18, 2012

Model View Control version of Tip Calculator

The model view control pattern is basic to object oriented programming. It has the advantage of separating out functionality

The Model

The model handles all the data processing. In our case this means the tip class itself with its methods for calculating the tip, the tax and the total. But it can also mean classes that access files or databases

The View

The view is the display part of the program. It could be console, or web, Android xml or in our case Swing. The view is only concerned with getting user input and displaying results. No calculations are performed in the view

The Controller

The controller's responsibility is to transfer the data from the model to the view.

In this example, the main, located in the class program, instantiates the view, the model and the controller and passes the view and model to the controller for processing.

Classes are fairly loosely coupled. The view is unaware of either the model or the controller. The model is unaware of the controller or the view. Only the controller needs to be aware of the other components and they are passed as objects to it through its constructor.

The program behaves exactly like the other examples.



Here is the UML class diagrams for the Model View Control version of this project



Here is the code for the various classes


program.java

import javax.swing.*;

public class program {

 /*******************************
  * this class has the main method.
  *It instantiates the view, the model and 
  *the controller. It passes the view
  *and the model to the controller
  */
 public static void main(String[] args) {
  TipModel model = new TipModel();
  JFrameView view = new JFrameView();
  
  TipController  controller = new TipController(view, model);
  view.setBounds(100,100,500,300);
  view.setTitle("Tip Calculator MVC");
  view.setVisible(true);
  
 }

}

JFrameView.java

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

import java.awt.*;
import java.awt.event.ActionListener;


public class JFrameView extends JFrame{
 
 /**
  * this method creates the JFrame
  * and adds the Panel
  * the panel is actually the main part of the view
  * I have combined the two into one class
  * to make it simpler, so we just have one
  * view class
  * the view is unaware of the model or the 
  * controller, although it knows its listener
  * methods must be sent in from somewhere else
  */
 private JPanel panel;
 
 JPanel buttonPanel;
 JLabel lblAmount;
 JRadioButton tenPercent;
 JLabel choosePercent;
 JRadioButton fifteenPercent;
 JRadioButton twentyPercent;
 JRadioButton rbother;
 JTextField txtOther;
 JLabel lbltax;
 JLabel lblTip;
 JLabel lblTaxPercent;
 JLabel lblTaxAmt;
 JLabel lblTotal;
 JTextField txtAmount;
 JTextField txtTaxPercent;
 JTextField txtTipAmount;
 JTextField txtTaxAmount;
 JTextField txtTotal;
 JLabel lblOther;
 
 JButton calculate;
 JButton exit; 
 
 
 
 double tipPercent;
 double amount;
 double taxPercent;
 
 private static final long serialVersionUID = 1L;

 //constructor
 public JFrameView(){
  JFrame frame=new JFrame();
  frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
  //call the method that builds the panel
  buildPanel();
   
  
  
 
 }
 
 public void buildPanel(){
  
  //instantiate all the objects
  //and set their properties
  panel=new JPanel();
  panel.setLayout(new GridLayout(10,2,5,5));
  
  lblAmount = new JLabel("Enter pre-tax amount:");
  
  txtAmount=new JTextField(10);
  
  tenPercent=new JRadioButton("Ten Percent");
    
  fifteenPercent=new JRadioButton("Fifteen Percent");
  fifteenPercent.setSelected(true);
    
  twentyPercent = new JRadioButton("twenty Percent");
    
  rbother =new JRadioButton("Other");
 
  //add radiobuttons to a button group
  ButtonGroup group = new ButtonGroup();
  group.add(tenPercent);
  group.add(fifteenPercent);
  group.add(twentyPercent);
  group.add(rbother);
  
  lblOther=new JLabel("Enter Other Percent");
  
  txtOther = new JTextField(10);
  
  lblTaxPercent=new JLabel("Enter tax Percent:");
  
  txtTaxPercent=new JTextField(10);
  
  lblTip = new JLabel("Tip Amount:");
  
  txtTipAmount = new JTextField(10);
  txtTipAmount.setEditable(false);
  
  lblTaxAmt = new JLabel("Tax Amount:");
  
  txtTaxAmount =new JTextField(10);
  txtTaxAmount.setEditable(false);
  
  lblTotal = new JLabel("Total:");
  
  txtTotal = new JTextField(10);
  txtTotal.setEditable(false);
  //add all the components 
  //except the buttons to the panel
  
  panel.add(lblAmount);
  panel.add(txtAmount);
  
  panel.add(tenPercent);
  panel.add(fifteenPercent);
  panel.add(twentyPercent);
  panel.add(rbother);
  panel.add(lblOther);
  panel.add(txtOther);
  panel.add(lblTaxPercent);
  panel.add(txtTaxPercent);
  panel.add(lblTip);
  panel.add(txtTipAmount);
  panel.add(lblTaxAmt);
  panel.add(txtTaxAmount);
  panel.add(lblTotal);
  panel.add(txtTotal);
  
  
  
  //add a second panel
  //this one uses flow layout
  buttonPanel = new JPanel();
  buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
  
  //instantiate the buttons and add 
  //them to the panel
  //also add a listener
  calculate = new JButton("Calculate");
  //calculate.addActionListener(this);
  buttonPanel.add(calculate);
  
  exit = new JButton("Exit");
  //exit.addActionListener(this);
  buttonPanel.add(exit);
  
  //this, in this case the window
  //we add the two panels to a border
  //layout the main one is in the center
  //the button panel is below (SOUTH)
  this.setLayout(new BorderLayout());
  this.add(panel, BorderLayout.CENTER);
  this.add(buttonPanel, BorderLayout.SOUTH);

}
 
public double GetAmount(){
 //get the strings from the text boxes
 double amount=0;
 try{
 String strAmount=txtAmount.getText();
  amount= Double.parseDouble(strAmount);
 
 }
 catch (Exception e){
  lblTotal.setText(e.getMessage());
 }
 return amount;
}

public double getTipPercent(){
 tipPercent=0;
 
 //check which radio button is selected
 if(tenPercent.isSelected())
  tipPercent=.1;
 else if(fifteenPercent.isSelected())
  tipPercent=.15;
 else if (twentyPercent.isSelected())
  tipPercent=.2;
 else if (rbother.isSelected()){
  String percent=txtOther.getText();
  //there is a chance the parse can fail
  try{
  tipPercent=Double.parseDouble(percent);
  }
  catch(Exception e){
   lblTotal.setText(e.getMessage());
  }
 }
 else
  tipPercent=0;
 return tipPercent;
}

public double getTaxPercent(){
 String taxPerc = txtTaxPercent.getText();
 try{
 taxPercent=Double.parseDouble(taxPerc);
 }
 catch(Exception e){
  lblTotal.setText(e.getMessage());
 }
 return taxPercent;
}

public void setTotal(String total){
 lblTotal.setText(total);
}

public void setTip(String tip){
 lblTip.setText(tip);
}

public void setTax(String tax){
 lblTaxAmt.setText(tax);
}

//these are different rather than implement
//the listeners here the controller will return the 
//listener to the view
public void addCalculateListener(ActionListener cal){
 calculate.addActionListener(cal);
}

public void addExitListener(ActionListener el){
 exit.addActionListener(el);
}
}

TipController.java

import java.awt.event.*;
import javax.swing.*;

public class TipController {
 
 /******************************
  * So this is the controller. It gets both
  * the model and the view from the program
  * class which contains the main() method
  * It implements two internal classes
  * as listeners
  */
 private JFrameView m_view;
 private TipModel m_model;
 
 public TipController (JFrameView view, TipModel model){
  m_view=view;
  m_model=model;
  
  //here it returns the listeners to the view
  view.addCalculateListener(new CalculateListener());
  view.addExitListener(new ExitListener());
 }
 
 class CalculateListener implements ActionListener{
  
  public void actionPerformed(ActionEvent e){
   //get the user's input values from the view's form
   double amt=m_view.GetAmount();
   double tPercent=m_view.getTipPercent();
   double taxPerc=m_view.getTaxPercent();
   
   //set the values in the model
   m_model.setPreTaxAmount(amt);
   m_model.setTipPercent(tPercent);
   m_model.setTaxPercent(taxPerc);
   
   //do the calculations and pass them back to the view
   //I did both in single statements
   m_view.setTip(Double.toString(m_model.CalculateTip()));
   m_view.setTax(Double.toString(m_model.CalculateTax()));
   m_view.setTotal(Double.toString(m_model.CalculateTotal()));
   
  }
 }
 
 class ExitListener implements ActionListener{
  
  public void actionPerformed(ActionEvent e){
   System.exit(0);
  }
 }
}


TipModel.java


public class TipModel {
/*************************
 * this is the model class. It handles the data
 * and does all the calculations. It is totally
 * independent of the controller and the view
 * it is identical to the tip class in the 
 * former version
 */
 //private fields
 private double preTaxAmount;
 private double tipPercent;
 private double taxPercent;
 
 //constructors
 public TipModel(){
  preTaxAmount=0;
  tipPercent=0;
  taxPercent=0;
 }
 
 public TipModel(double preTaxAmount, double tipPercent, double taxPercent){
  this.setPreTaxAmount(preTaxAmount);
  this.setTipPercent(tipPercent);
  this.setTaxPercent(taxPercent);
 }
 
 
 //assessors/mutators
 public void setPreTaxAmount(double preTaxAmount) {
  this.preTaxAmount = preTaxAmount;
 }
 public double getPreTaxAmount() {
  return preTaxAmount;
 }
 public void setTipPercent(double tipPercent) {
  //make sure the tip is a decimal
  //or zero
  if (tipPercent >=1)
   tipPercent /= 100;
  this.tipPercent = tipPercent;
 }
 public double getTipPercent() {
  return tipPercent;
 }
 public void setTaxPercent(double taxPercent) {
  if(taxPercent >=1)
   taxPercent /=100;
  this.taxPercent = taxPercent;
 }
 public double getTaxPercent() {
  return taxPercent;
 }
 
 //public methods
 public double CalculateTip(){
  return preTaxAmount * tipPercent;
 }
 
 public double CalculateTax(){
  return preTaxAmount * taxPercent;
 }
 
 public double CalculateTotal(){
  return preTaxAmount + (preTaxAmount * tipPercent)
    + (preTaxAmount * taxPercent);
 }
 
 

}

No comments:

Post a Comment