-1

I have Java Swing application which is designed in poor architecture. GUI, SQL Statement ... etc, all one class. Ex. NewEmployee.java have GUI, SQL insert,update,delete & select in this class, there is no separation. From what I read we should separate the logic from the design. To be honest I don't know how to do that, or how to understand it.

I need to know how to break down my project so I got : model, view & controller, but I need to know what each one mean & how each one should cooperate with other.

could you help in separating this:

    public class PendingOInvoices extends CFrame {

    private static final long serialVersionUID = 1L;
    private JToolBar toolBar = new JToolBar();
    private JPanel panel_1 = new JPanel();
    private JLabel label3 = new JLabel();
    private CText cSearch = new CText();
    private JLabel label2 = new JLabel();
    private CDCombo cSearchBy = new CDCombo();
    private CBGeneral cMakeBill = new CBGeneral();
    private Component component5_1 = Box.createHorizontalStrut(3);
    private CBRefreshE cRefresh = new CBRefreshE();
    private CBCloseE cClose = new CBCloseE();
    private Component component5_3 = Box.createHorizontalStrut(3);
    private JLabel label1 = new JLabel();
    private CDate cTDate = new CDate();
    private MyOutBillingModel model1 = new MyOutBillingModel();
    private JPVTableView table1 = new JPVTableView(model1);
    private JLabel label = new JLabel();
    private CDate cFDate = new CDate();
    private CBNewE cNew = new CBNewE();
    private CBModifyE cModify = new CBModifyE();
    private Component component5 = Box.createHorizontalStrut(3);
    private Component component5_2 = Box.createHorizontalStrut(3);
    private JLabel label4 = new JLabel();
    private CDCombo cFilter = new CDCombo();

    public PendingOInvoices () {

        setTitle("Out Patients - Pending Encounters");
        setFrameIcon("opdbilling");

        try {
            jbInit();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

  private void jbInit() throws Exception {
      setSize(new Dimension(980, 546));
      getContentPane().setLayout(new BorderLayout());      
      getContentPane().add(panel_1, BorderLayout.NORTH);
      panel_1.setMaximumSize(new Dimension(0, 44));
      panel_1.setMinimumSize(new Dimension(0, 44));
      panel_1.setLayout(null);
      panel_1.setPreferredSize(new Dimension(0, 44));

      panel_1.add(label3);
      label3.setText("Search engine:");
      label3.setBounds(790, 0, 170, 19);

      panel_1.add(cSearch);
      cSearch.addKeyListener(new CSearchKeyListener());
      cSearch.setBounds(790, 20, 170, 23);

      panel_1.add(label2);
      label2.setText("Search by:");
      label2.setBounds(662, 0, 127, 19);

      panel_1.add(cSearchBy);
      cSearchBy.addActionListener(new CSearchByActionListener());
      cSearchBy.setBounds(662, 20, 127, 23);

      cSearchBy.addItem("ID No");
      cSearchBy.addItem("File No");
      cSearchBy.addItem("Patient Name (EN)");
      cSearchBy.addItem("Patient Name (ع)");
      cSearchBy.addItem("Encounter No");

      toolBar.setBounds(0, 0, 264, 45);
      panel_1.add(toolBar);
      toolBar.setFloatable(false);

      toolBar.add(cRefresh);     
      toolBar.add(component5_1);
      toolBar.add(cNew);
      cNew.addActionListener(new CNewActionListener());
      toolBar.add(component5_3);
      toolBar.add(cModify);      
      cModify.addActionListener(new CModifyActionListener());
      toolBar.add(component5);
      toolBar.add(cMakeBill);
      cMakeBill.setText("Make Bill");

      cRefresh.addActionListener(new CRefreshActionListener());
      cMakeBill.setIcon(SwingResourceManager.getIcon(PendingOInvoices.class, "/images/small/billmaker.png"));
      cMakeBill.addActionListener(new CMakeBillActionListener());

      toolBar.add(component5_2);
      toolBar.add(cClose);
      cClose.addActionListener(new CCloseActionListener());

      panel_1.add(label1);
      label1.setText("To Date:");
      label1.setBounds(382, 0, 115, 19);

      panel_1.add(cTDate);
      cTDate.addTextListener(new CTDateTextListener());
      cTDate.addKeyListener(new CTDateKeyListener());
      cTDate.setBounds(382, 20, 115, 23);

      getContentPane().add(table1);
      table1.getJTable().addMouseListener(new table1JTableMouseListener());
      table1.getJTable().addKeyListener(new Table1JTableKeyListener());
      cSearch.setHorizontalAlignment(SwingConstants.CENTER);

      panel_1.add(label);
      label.setText("From Date:");
      label.setBounds(266, 0, 115, 19);

      panel_1.add(cFDate);
      cFDate.setText("01/01/"+cTDate.getText().substring(7));
      cFDate.addTextListener(new CFDateTextListener());
      cFDate.addKeyListener(new CFDateKeyListener());
      cFDate.setBounds(266, 20, 115, 23);

      panel_1.add(label4);
      label4.setText("Filtering Options:");
      label4.setBounds(498, 0, 163, 19);

      panel_1.add(cFilter);
      cFilter.addActionListener(new CFilterActionListener());
      cFilter.setBounds(498, 20, 163, 23);

      cFilter.addItem("--- Choose ---");
      cFilter.addItem("Guarantors Shares Only");
      cFilter.addItem("Cash Patients Only");
      cFilter.addItem("Patients Got Discount Only");

      setWidths();
      fillEncounters();
  }

  public void updateMe(String encno){
      fillEncounters();
      table1.getTable().requestFocus();
      table1.getTable().setFocusCell(table1.search(encno, 1),1);
  }

  private void setWidths() {

      model1.setColumnCount(9);
      model1.setRowCount(0);

      table1.getColumn(0).setPreferredWidth(75);
      table1.getColumn(1).setPreferredWidth(90);
      table1.getColumn(2).setPreferredWidth(350);
      table1.getColumn(3).setPreferredWidth(80);
      table1.getColumn(4).setPreferredWidth(80);
      table1.getColumn(5).setPreferredWidth(80);
      table1.getColumn(6).setPreferredWidth(80);
      table1.getColumn(7).setPreferredWidth(80);
      table1.getColumn(8).setPreferredWidth(20);

      table1.getColumn(0).setHeaderValue("Date");
      table1.getColumn(1).setHeaderValue("Encounter No");
      table1.getColumn(2).setHeaderValue("Patient Name");
      table1.getColumn(3).setHeaderValue("Total");
      table1.getColumn(4).setHeaderValue("Guarantors");
      table1.getColumn(5).setHeaderValue("Discount");
      table1.getColumn(6).setHeaderValue("Paid");
      table1.getColumn(7).setHeaderValue("Balance");
      table1.getColumn(8).setHeaderValue("");

      table1.setColumnType(0, JPVTable.DATE, null);
      table1.setColumnType(1, JPVTable.DATE, null);
      table1.setColumnType(2, JPVTable.TEXT, null);
      table1.setColumnType(3, JPVTable.DOUBLE, null);
      table1.setColumnType(4, JPVTable.DOUBLE, null);
      table1.setColumnType(5, JPVTable.DOUBLE, null);
      table1.setColumnType(6, JPVTable.DOUBLE, null);
      table1.setColumnType(7, JPVTable.DOUBLE, null);
      table1.setColumnType(8, JPVTable.BOOLEAN, null);

      CTableConfig mc = new CTableConfig();
      mc.newConfigureTable(table1,8,0,true);

      table1.getTable().getColumnModel().getColumn(8).setHeaderRenderer(new CHGeneral(new MyItemListener()));
  }

  class MyItemListener implements ItemListener {
      public void itemStateChanged(ItemEvent e) {
        Object source = e.getSource();
        if (!(source instanceof AbstractButton)) return;
        boolean checked = e.getStateChange() == ItemEvent.SELECTED;
        int rows = model1.getRowCount();
            for(int x = 0; x < rows; x++){
                model1.setValueAt(checked,x,8);
        }
      }
  }

  private String getSearchColumn(){
      if(cSearchBy.getSelectedIndex() == 0){
          return "patients.PatID";
      }else if(cSearchBy.getSelectedIndex() == 1){
          return "encounters.Enc_Patient";
      }else if(cSearchBy.getSelectedIndex() == 2){
          return "concat(patients.PatFirst,' ', patients.PatFather,' ',patients.PatMiddle,' ',patients.PatFamily)";
      }else if(cSearchBy.getSelectedIndex() == 3){
          return "concat(patients.PatFirstA,' ', patients.PatFatherA,' ',patients.PatMiddleA,' ',patients.PatFamilyA)";
      }else if(cSearchBy.getSelectedIndex() == 4){
          return "encounters.Enc_No";
      }
      return "";
  }

  private void fillEncounters(){
      String currentValue = "";
      int r = table1.getTable().getFocusRow();

      cFDate.setFormat(2);
      cTDate.setFormat(2);

      String sql = "SELECT \n"
          +"Date_Format(Enc_Date,'%d/%m/%Y'), \n"
          +"encounters.Enc_No, \n"
          +"CONCAT(' ',patients.PatFirst,' ',patients.PatFather,' ',patients.PatMiddle,' ',patients.PatFamily), \n"
          +"FORMAT((Enc_Clinics+Enc_Labs+Enc_Rads+Enc_MED),2), \n"
          +"FORMAT(Enc_Guarantor,2), \n"
          +"FORMAT(Enc_Discount,2), \n"
          +"FORMAT((Enc_Receipt-Enc_Payment),2), \n"
          +"FORMAT(Enc_Balance,2), \n"
          +""+Boolean.FALSE+", \n"
          +"encounters.Enc_Patient, \n"
          +"VERSION \n"
          +"FROM \n"
          +"encounters \n"
          +"INNER JOIN encsummary ON encounters.Enc_No = encsummary.Enc_No \n"
          +"INNER JOIN patients ON encounters.Enc_Patient = patients.PatNo \n"
          +"WHERE Enc_Date Between '"+cFDate.getText()+"' AND '"+cTDate.getText()+"' AND Enc_Billed = 'false' \n"
          +"AND (Enc_Clinics+Enc_Labs+Enc_Rads+Enc_MED) > 0 \n";

                if(cFilter.getSelectedIndex() == 1){
                    sql+="and Enc_Guarantor > 0 \n";
                }else if(cFilter.getSelectedIndex() == 2){
                    sql+="and Enc_Guarantor = 0 \n";
                }else if(cFilter.getSelectedIndex() == 3){
                    sql+="and Enc_Discount > 0 \n";
                }
                if(cSearch.getText().trim().length() > 0){
                   sql+= "and "+getSearchColumn()+" LIKE '%"+cSearch.getText()+"%' \n";
                }

                sql+="Order By encounters.Enc_No DESC";
                      cFDate.setFormat(1);
                      cTDate.setFormat(1);
                      model1.setData(CDeclare.dataAccessor.getData(sql));
                try{
                  currentValue = table1.getValueAt(r, 1).toString();
                }catch(Exception ex){}
                int i = table1.search(currentValue, 1);
                table1.getTable().scrollRectToVisible(new Rectangle(table1.getTable().getCellRect(i, 1, true)));
                table1.getTable().changeSelection(i, 1, false, false);
  }

  private class CSearchByActionListener implements ActionListener {
    public void actionPerformed(ActionEvent arg0) {
        cSearchBy_actionPerformed(arg0);
    }
  }
  private class table1JTableMouseListener extends MouseAdapter {
    public void mouseClicked(MouseEvent arg0) {
        table1JTable_mouseClicked(arg0);
    }
  }
  private class CMakeBillActionListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        cMakeBill_actionPerformed(e);
    }
  }
  private class CSearchKeyListener extends KeyAdapter {
    public void keyReleased(KeyEvent e) {
        cSearch_keyReleased(e);
    }
  }
  private class CTDateKeyListener extends KeyAdapter {
    public void keyReleased(KeyEvent e) {
        cTDate_keyReleased(e);
    }
  }
  private class CRefreshActionListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        cRefresh_actionPerformed(e);
    }
  }
  private class CTDateTextListener implements TextListener {
    public void textValueChanged(TextEvent e) {
        cTDate_textValueChanged(e);
    }
  }
  private class CCloseActionListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        cClose_actionPerformed(e);
    }
  }
  private class CFDateKeyListener extends KeyAdapter {
    public void keyReleased(KeyEvent e) {
        cFDate_keyReleased(e);
    }
  }
  private class CFDateTextListener implements TextListener {
    public void textValueChanged(TextEvent e) {
        cFDate_textValueChanged(e);
    }
  }
  private class CNewActionListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        cNew_actionPerformed(e);
    }
  }
  private class CModifyActionListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        cModify_actionPerformed(e);
    }
  }
  private class Table1JTableKeyListener extends KeyAdapter {
    public void keyPressed(KeyEvent e) {
        table1JTable_keyPressed(e);
    }
  }
  private class CFilterActionListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        cFilter_actionPerformed(e);
    }
  }

    protected void cSearchBy_actionPerformed(ActionEvent arg0) {
        if(cSearchBy.getSelectedIndex() == 3){
              cSearch.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        }else{
              cSearch.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
        }
        cSearch.setText(null);
    }

    protected void table1JTable_mouseClicked(MouseEvent e) {
        int c = table1.getTable().getSelectedColumn();
        if(e.getClickCount() >= 2 && c != 8){
            cModify_actionPerformed(null);
        }
    }

    private void insertInvoice(){

         double total = 0,guarantors = 0,grandtotal = 0;
         CDate datg = new CDate();
         String encno = "",invno = "",version = "";

         for(int i = 0; i < model1.getRowCount();i++){
             if(model1.getValueAt(i, 8).equals(Boolean.TRUE)){
                 if(datg.getFormat() != 1){
                     datg.setFormat(1);
                 }
                 encno = model1.getValueAt(i, 1).toString();
                 version = model1.getValueAt(i, 10).toString();

                 if(!CDeclare.SAMEVERSION("encounters","Enc_No",encno,version)){
                     return;
                 }
                 CDeclare.dataAccessor.UpdateDB("update encounters set VERSION = (VERSION+1) WHERE Enc_No = '"+encno+"'");
                 CDeclare.doubleValue.setValue(model1.getValueAt(i,3));
                 total = CDeclare.doubleValue.getDouble();

                 CDeclare.doubleValue.setValue(model1.getValueAt(i,4));
                 guarantors = CDeclare.doubleValue.getDouble();

                 grandtotal = total-guarantors;

                 invno = CDeclare.newNumber.getLastYearMonthNo(datg, "LastTemp");
                 datg.setFormat(2);

     String sql = " Insert into invoice(Inv_No,Inv_Entry_Date,Inv_Kind,Inv_ClientKind,Inv_ClientSubKind,Inv_SubRefNo,Inv_Name,Inv_Date," +
                  "Inv_VatPercent,Inv_SubTotal,Inv_OthersTotal,Inv_Total,EMPIII) values (" +
                  "'" + invno + "'," +
                  "'" + CDeclare.getServerDateMySSQL() + "'," +
                  "'" + "S" + "'," +
                  "'" + "P" + "'," +
                  "'" + "OP" + "'," +
                  "'" + encno + "'," +
                  "'" + model1.getValueAt(i, 9) + "'," +
                  "'" + datg.getText() + "'," +
                  "'" + CDeclare.VAT + "'," +
                  "'" + total + "'," +
                  "'" + guarantors + "'," +
                  "'" + grandtotal + "'," +
                  "'" + CDeclare.EMPNO + "'" + ")";

         CDeclare.dataAccessor.InsertDB(sql);
         insertInvDetails(encno,invno);

             }
         }
    }

    private void insertInvDetails(String encno,String invno){
         CCurrency vat = new CCurrency();

         String invDetSql = "SELECT \n"
                           +"Sec_Account, \n"
                           +"Sec_Department, \n"
                           +"Ch_Kind, \n"
                           +"FORMAT((SUM(Ch_Total)/("+(1+CDeclare.VAT)+")),2), \n"
                           +"FORMAT(SUM(Ch_Total),2) \n"
                           +"FROM \n"
                           +"enccharges \n"
                           +"INNER JOIN medicalsections ON Ch_Section = Sec_No \n"
                           +"WHERE \n"
                           +"Ch_EncNo = '"+encno+"' \n"
                           +"GROUP BY Ch_Kind,Sec_Account,Sec_Department for update \n";
         Vector<?> data = CDeclare.dataAccessor.getData(invDetSql);
         for(int i = 0; i < data.size(); i++){
         Vector<?> v = (Vector<?>) data.elementAt(i);

         CDeclare.myDouble.setValue(v.elementAt(4));
         CDeclare.doubleValue.setValue(v.elementAt(3));

         vat.setDouble(vat.getDouble()+CDeclare.myDouble.getDouble()-CDeclare.doubleValue.getDouble());

         String insSql = "Insert into invoicedetails(Inv_No,Inv_Account,Inv_Department,Inv_Kind,Inv_Total,Inv_TaxTotal) values (" +
                         "'" + invno + "'," +
                         "'" + v.elementAt(0) + "'," +
                         "'" + v.elementAt(1) + "'," +
                         "'" + v.elementAt(2) + "'," +
                         "'" + CDeclare.doubleValue.getDouble() + "'," +
                         "'" + CDeclare.myDouble.getDouble()+ "'" + ")";

          CDeclare.dataAccessor.InsertDB(insSql);
         }
         CDeclare.dataAccessor.UpdateDB("update invoice set Inv_Vat = '"+vat.getDouble()+"' where Inv_No = '"+invno+"'");

         String sqlUpdateEncounter = " Update encounters set \n" +
                                     " Enc_Billed = 'true',\n" +
                                     " Enc_Status = 'D',\n" +
                                     " Enc_BillNo = '" + invno + "'\n " +
                                     " where Enc_No = '" + encno + "'";

         CDeclare.dataAccessor.UpdateDB(sqlUpdateEncounter);
    }

    protected void cMakeBill_actionPerformed(ActionEvent e) {

        int option = (new CConfirms()).getSelection('S',"This operation will generate temporary invoices for selected encounters \n Are you sure ?!!!");
        if(option != 0){
            return;
        }

        CDeclare.dataAccessor.initAutoCommit();
        CDeclare.dataAccessor.beginTransaction();

        insertInvoice();

        if(CDeclare.exCounter == 0){
           CDeclare.dataAccessor.endTransaction();
           fillEncounters();
        }else{
           CDeclare.dataAccessor.rollBack();
           new CAlerts('D');
        }
    }

    protected void cSearch_keyReleased(KeyEvent e) {
        fillEncounters();
    }
    protected void cTDate_keyReleased(KeyEvent e) {
        if(cTDate.getText().length() == 10){
            fillEncounters();
        }
    }

    protected void cRefresh_actionPerformed(ActionEvent e) {
        fillEncounters();
    }

    protected void cTDate_textValueChanged(TextEvent e) {
        if(cTDate.getText().length() == 10){
           fillEncounters();
        }
    }

    protected void cClose_actionPerformed(ActionEvent e) {
        dispose();
    }
    protected void cFDate_keyReleased(KeyEvent e) {
        if(cFDate.getText().length() == 10){
           fillEncounters();
        }
    }
    protected void cFDate_textValueChanged(TextEvent e) {
        if(cFDate.getText().length() == 10){
           fillEncounters();
        }
    }
    protected void cNew_actionPerformed(ActionEvent e) {
        NewEncounter newr = new NewEncounter(getTitle() + " - "+cNew.getText());
        newr.insertMode();
        newr.setOwner(this);
        newr.setVisible(true);
    }
    protected void cModify_actionPerformed(ActionEvent e) {
        int r = table1.getTable().getFocusRow();
        String encno = model1.getValueAt(r,1).toString();

        NewEncounter newr = new NewEncounter(getTitle() + " - "+cModify.getText());
        newr.modifyMode();
        newr.setOwner(this);
        newr.fillEncounter(encno);
        newr.setVisible(true);
    }
    protected void table1JTable_keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_ENTER){
            e.consume();
            cModify_actionPerformed(null);
        }
    }
    protected void cFilter_actionPerformed(ActionEvent e) {
        fillEncounters();
    }
}

class MyOutBillingModel extends PVTableModel {
    private static final long serialVersionUID = 1L;
    public boolean isCellEditable(int iRow, int iCol) {
      try{
          if(iCol == 8){
              return true;
          }
      }catch(Exception ex){}
      return false;
    }
BenMorel
  • 34,448
  • 50
  • 182
  • 322
  • Classes hold references to other classes they need. Methods are called on those classes. Thats all that can really be said without a specific problem – Richard Tingle Oct 26 '13 at 11:24

4 Answers4

2

Your on the right track if you know what MVC is. You may also want to look at MVVM as it has the same goal. Let's break it down:

  • Model - simple classes with getter/setters and no logic or details about storage
  • View - classes or pages that display Model data in some organized way
  • Controller - the object that accepts actions from the View, manipulates Model, and transfers control to a new View (passing it a Model)

In general what we like to do is first "model" the data into classes that have no business logic, UI concepts or storage dependencies (like SQL). They are simple objects with getter/setter for data. Then the "view" classes/pages are designed so they know how to read those model objects and display them in whatever way makes sense. But the view does not know where/how those model objects are stored. The glue that puts the view and model together is the "controller", which is why it has that name. Typically the user interacts with the view to get/change data, and the view then invokes the controller with an "action" like "get-employee". The control is the only thing that knows what the action means and what to do. In the simple case, the controller will go get the data from the storage, and then decide on what the next view should be for the user. It takes the model object it loaded from storage, constructs the view, and passes the model to the view where it is rendered. The key point here is that the first view has no idea of what the controller is going to do and has no idea what the next view will be. That's all the business of the controller.

So in your case, you might have a few Employee Views like NewEmployee, EmployeeDetails, EmployeeListing. And then you might have a Model like Employee. You should be able to build these views with no SQL. That's how you know you are doing this right. Then, you introduce the Controller, like an EmployeeController. Then, you tie Button presses and click events in your Views to the action methods on the Controller. So you can add methods like this:

View listEmployees()
View createEmployee(Employee e)
View getEmployee(long id)
View deleteEmployee(long id)

Your Controller should then be the only component that interacts with storage, and then decides on what the "next" View should be. That's why it returns a View and not the Model. For instance, the method might look something like this:

public class EmployeeController {
  . . .
  public View listEmployees() {
    List<Employee> employees = storage.getAllEmployees();
    return new EmployeeListing(employees); 
  }
}

That's the basic concept and how the separation works. In most real MVC/MVVC frameworks, there is more sophistication around the mapping of actions and views.

Notice I also added a "storage" object so that even the Controller does not know that SQL is used. That will lead you to concepts like DAO which is how to abstract the actual storage details away from the rest of the app, if you want to.

Jerico Sandhorn
  • 1,880
  • 1
  • 18
  • 24
1

Model View Controller (MVC) is a concept you may want to use. More about that in here: How to correctly implement swing-Please check the accepted answer in this link.

In your case, don't break the working code unless you have to...Remember that such a design change may cost more that its worth for a running system.

Community
  • 1
  • 1
NoChance
  • 5,632
  • 4
  • 31
  • 45
1

Start by separating all the SQL code into a separate package with interfaces and implementations. You can test those without the UI and put them aside.

Then I'd recommend making all the Swing classes another separate package. Do not call new to create and attach Listeners in the Swing classes. Instead, provide a mechanism for passing them in via constructors or setters. Inject those dependencies.

Model classes ought to represent the problem you're solving without a UI or database. See if they do.

Last have the controller package with classes that instantiate the listeners and views, gives the views the listeners they need, and fulfill the use cases by manipulating model and persistence objects.

That's MVC.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • Aha, The main goal of doing this saparation is to make the application run as 3-tier application, one more issue i have, what i can use for mid-tier between the application & the MySQL server? there is confusing in doing that. could you please explain to me how i can implement Middle tier? How to implement on the client application & how to implement on the server side. – Ameera Khaleel Oct 26 '13 at 11:42
  • Yes, you can do it, but you'll have to make the view and the middle tier communicate. Have you thought about how to do that? Since both sides are Java, one choice is RMI. Your Listeners will be RMI clients that talk to RMI servers on the controller. – duffymo Oct 26 '13 at 11:50
  • OK, Could you please explain to me (RMI Servers)? is it mean server on the network other than the mysql server? if that correct, just please explain it to me, since i start to understand the whole idea, but with some confusing parts. – Ameera Khaleel Oct 26 '13 at 12:00
  • Sorry Ameera, this is on you. SO is a Q&A forum, not a tutoring site. RMI is a client/server protocol that uses sockets, built into Java. It's the Java equivalent of something called CORBA, a 90s technology that's fallen out of favor now that we have HTTP. You have to do some research and work now. – duffymo Oct 26 '13 at 12:03
  • You should consider using RESTful HTTP servers with JSON. That's the most popular, simple and portable way to do this. That way, your middle tier can be in any language and your front-end will work with any middleware solution as long as it has the same URL/JSON api. – Jerico Sandhorn Oct 26 '13 at 12:04
  • This is a person who doesn't understand MVC. I agree with your point - it's spot on - but I don't know if Ameera is up to the task. – duffymo Oct 26 '13 at 12:06
0

from what i read we should separate the logic from the design. to be honest i don't know how to do that, or how to understand it.

The main reason (beyond the usual "cleaner code and architecture") why you want to do that and the principles behind can be explained best on an example.

Let's assume, you have a nice working desktop UI application. Now you want to create a web version of the very same application.

When the GUI application has placed all the business logic and all the DB accesses in the forms (or whatever the equivalent is), you got a problem. Because everything is coupled so tightly together, it is virtually impossible to re-use anything from the GUI application. So you start duplicating your code, and that's a real bad-bad. That way you end up with two code bases which have to be maintained.

In order to get the most out of the reusing game, you want to separate (at least) the UI from the underlying business logic. And while we're at it, it is also not such a bad idea to split the levels of abstraction once more and extracting the data model.

Now we can do something like this:

+-----------+
|  Web UI   |<<------+
+-----------+        |
                     |       +-----------+        +------------+
                     +----->>| Biz Logic |<<---->>| Data Model |
                     |       +-----------+        +------------+
+-----------+        |
|    GUI    |<<------+
+-----------+

To achieve that, you have to do certain things:

  1. split the code accordingly to have independent (code) modules
  2. remove all dependencies from right hand parts to left hand parts (ie. logic should not know anything about the UI details)

Methodical frameworks like MVC or MVVM or others can be considered as best-practice toolbelts to support you doing that at the interface between the logic and the UI parts. These concepts are proven and have matured over a long time. Strictly speaking, it is not required that you follow these concepts, but it is strongly recommended, as they not only help with architectural decisions but also and the make day-to-day coding work much easier, because of the existing framework implementations (again, that varies on what language etc. is used).

JensG
  • 13,148
  • 4
  • 45
  • 55