-1

貧弱なアーキテクチャで設計された Java Swing アプリケーションがあります。GUI、SQL ステートメントなど、すべて 1 つのクラスです。元。NewEmployee.java には GUI、SQL の挿入、更新、削除、および選択がこのクラスにあり、分離はありません。私が読んだことから、ロジックを設計から分離する必要があります。正直なところ、私はそれを行う方法、またはそれを理解する方法がわかりません。

プロジェクトを分解する方法を知る必要があるため、モデル、ビュー、コントローラーを取得しましたが、それぞれが何を意味し、それぞれがどのように連携する必要があるかを知る必要があります。

これを分離するのを手伝ってもらえますか:

    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;
    }
4

4 に答える 4

2

MVCとは何かを知っていれば、正しい軌道に乗っています。同じ目標を持っているため、MVVM も確認することをお勧めします。それを分解しましょう:

  • モデル - ゲッター/セッターを備えたシンプルなクラスで、ストレージに関するロジックや詳細はありません
  • ビュー - モデル データを何らかの方法で表示するクラスまたはページ
  • コントローラー - ビューからのアクションを受け取り、モデルを操作し、制御を新しいビューに転送する (モデルを渡す) オブジェクト

一般的に、私たちがやりたいことは、まずデータを、ビジネス ロジック、UI の概念、ストレージの依存関係 (SQL など) を持たないクラスに "モデル化" することです。これらは、データのゲッター/セッターを備えた単純なオブジェクトです。次に、「ビュー」クラス/ページは、それらのモデル オブジェクトを読み取り、意味のある方法で表示する方法を理解できるように設計されます。しかし、ビューはそれらのモデル オブジェクトがどこにどのように格納されているかを知りません。ビューとモデルを結合する接着剤は「コントローラー」です。通常、ユーザーはビューを操作してデータを取得/変更し、ビューは「get-employee」などの「アクション」でコントローラーを呼び出します。コントロールは、アクションが何を意味し、何をすべきかを知っている唯一のものです。単純なケースでは、コントローラーはストレージからデータを取得します。次に、ユーザーにとっての次のビューを決定します。ストレージからロードしたモデル オブジェクトを取得し、ビューを構築して、モデルをレンダリングするビューに渡します。ここでの重要な点は、最初のビューはコントローラーが何をしようとしているのか分からず、次のビューがどうなるかも分からないということです。それがコントローラーのすべての仕事です。

したがって、あなたの場合、NewEmployee、EmployeeDetails、EmployeeListing などのいくつかの従業員ビューがあるかもしれません。そして、従業員のようなモデルがあるかもしれません。これらのビューは、SQL を使用せずに構築できるはずです。それが、あなたがこれを正しく行っていることを知る方法です。次に、EmployeeController のような Controller を導入します。次に、ビューのボタン プレス イベントとクリック イベントをコントローラーのアクション メソッドに結び付けます。したがって、次のようなメソッドを追加できます。

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

コントローラーは、ストレージと対話する唯一のコンポーネントである必要があり、「次の」ビューがどうあるべきかを決定します。そのため、モデルではなくビューを返します。たとえば、メソッドは次のようになります。

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

それが基本的な概念であり、分離がどのように機能するかです。ほとんどの実際の MVC/MVVC フレームワークでは、アクションとビューのマッピングがより洗練されています。

コントローラーでさえ SQL が使用されていることを認識しないように、「ストレージ」オブジェクトも追加したことに注意してください。必要に応じて、実際のストレージの詳細をアプリの残りの部分から抽象化する方法である DAO のような概念につながります。

于 2013-10-26T11:59:39.230 に答える
1

Model View Controller (MVC) は、使用したい概念です。詳細はこちら:スイングを正しく実装する方法 -このリンクで受け入れられた回答を確認してください。

あなたの場合、必要な場合を除いて、作業中のコードを壊さないでください...そのような設計変更は、実行中のシステムの価値よりも高くつく可能性があることに注意してください。

于 2013-10-26T11:30:06.320 に答える