优化策略模式,提高账薄显示的灵活性和扩展性

接着上一篇文章,账薄显示出来之后,为了提高软件的可扩展性和灵活性,我们应用策略设计模式。这不仅仅是为了提高代码的维护性,而是因为明细分类账账薄显示的后面有金额分析这个功能,从数据库后台分析及结合Java语言特性,类似数据转置,也是软件复杂度提出的一个客观优化需求。

定义策略接口

为了软件的简易性,我们采用拖拖拉拉就可形成各种界面元素的设计方式,它虽然降低的前端开发人员的难度,可以轻松应用CSS配置文件提高视图界面的灵活性,但后台的处理多了更多的规则。大的基本结构是一个控制器中同时又镶嵌多个控制器。所以,我们定义策略模式的接口如下:

java 复制代码
/**
 * 为了方便扩展,抽象显示方式,目前子类应该包括总分类账和明细分类账
 */
public interface ShowZhangBen {
    /**
     *
     * @param showZongZhangKeMu  要显示的账薄科目
     * @param keMuController 主科目界面的控制器
     * @throws IOException 由于从FXML文件加载要处理异常
     */
    void showZhangBo(KeMu showZongZhangKeMu, KeMuController keMuController) throws IOException;

}

实现基本的总分类账和明细分类账的接口实现类

当下业务需要二级科目已经满足要求,所以,我们先实现这两个策略实现类。按模式惯例,在科目主控制器中增加策略成员接口属性,然后点击科目,根据点击的科目不同,去自动的调用策略类的对应实现方式。之所以将策略做为成员属性,是因为不同的策略不光是显示方式的不同,包括后台处理和其它应该会有很多扩展类都会用引用到,所以没有从形式参数方法注入,而是从相应的策略实现类中去设置科目控制器成员属性;另一个考虑的这样做的原因是:在策略实现类中,有一次控制器重新从FXML文件加载的过程,这样加策略引用交付给主控制器,更好的体现了,子控制器不仅是一个控制器,同时是一个策略的双重角色,让主界面控制器的掌控能力更加充分。

具体的实现过程代码如下:

java 复制代码
  /**
     * 显示总分类账

     * @return 显示面板
     */
    @Override
    public void showZhangBo(KeMu showZongZhangKeMu, KeMuController keMuController) throws IOException {
        if (showZongZhangKeMu != null && showZongZhangKeMu.getKeMuLevel().equals("1"))        //总分类账
        {
            keMuController.setStrategyShowZhangBen(new ZhangBenController());

        }
        else if (showZongZhangKeMu != null && showZongZhangKeMu.getKeMuLevel().equals("2")) {
            keMuController.setStrategyShowZhangBen(new MingXiZhangController());

            keMuController.getStrategyShowZhangBen().showZhangBo(showZongZhangKeMu,keMuController);
            return;

        }

        FXMLLoader loader2 = new FXMLLoader();
        InputStream in = ZhangBenController.class.getResourceAsStream("/zhangBen/zhangBen.fxml");
        loader2.setBuilderFactory(new JavaFXBuilderFactory());
        loader2.setLocation(ZhangBenController.class.getResource("/zhangBen/zhangBen.fxml"));

        AnchorPane page;
        try {
            page = (AnchorPane) loader2.load(in);
            keMuController.setStrategyShowZhangBen(loader2.getController());

        } finally {
            in.close();
        }
        /**
         * 控制器自转移
         */
        lbeZhangbBoName=((ZhangBenController)keMuController.getStrategyShowZhangBen()).getLbeZhangbBoName();
        lvZongZhang=((ZhangBenController)keMuController.getStrategyShowZhangBen()).lvZongZhang;
        apZongZhang=((ZhangBenController)keMuController.getStrategyShowZhangBen()).apZongZhang;
        apZongZhangBo=((ZhangBenController)keMuController.getStrategyShowZhangBen()).apZongZhangBo;

        setShowKeMu(showZongZhangKeMu);


        lbeZhangbBoName.setText(showKeMu.getKeMuName()+"总分类账");
        List<ZongZhang> listData= getDataFromSpiZongZhang(showKeMu.getStrDbId());
        data = FXCollections.observableArrayList(listData);
        //给表格加上行数 2022-08-25
        TableColumn idCol = new TableColumn();
        idCol.setText("日期");
        idCol.setCellValueFactory(new PropertyValueFactory("recordDate"));
      //  idCol.setVisible(false);

        TableColumn taskIdCol = new TableColumn();
        taskIdCol.setText("凭证号数");
        taskIdCol.setCellValueFactory(new PropertyValueFactory("strPingZhengNo"));
        TableColumn costNameCol = new TableColumn();
        costNameCol.setText("摘要");
        costNameCol.setCellValueFactory(new PropertyValueFactory("strZhaiYao"));
        TableColumn thisAmountCol = new TableColumn();
        thisAmountCol.setText("√");
        thisAmountCol.setMinWidth(200);
        thisAmountCol.setCellValueFactory(new PropertyValueFactory("strCheckFlag"));
        TableColumn taskDateCol = new TableColumn();
        taskDateCol.setText("借方");
        taskDateCol.setMinWidth(200);
        taskDateCol.setCellValueFactory(new PropertyValueFactory("strJieFangAmount"));
        TableColumn employeeCol = new TableColumn();
        employeeCol.setText("贷方");
        employeeCol.setMinWidth(200);
        employeeCol.setCellValueFactory(new PropertyValueFactory("strDaiFangAmount"));
        TableColumn operDateCol = new TableColumn();
        operDateCol.setText("借或贷");
        operDateCol.setMinWidth(200);
        operDateCol.setCellValueFactory(new PropertyValueFactory("strAmountDirect"));
        TableColumn yuErCol = new TableColumn();
        operDateCol.setText("余额");
        operDateCol.setMinWidth(200);
        operDateCol.setCellValueFactory(new PropertyValueFactory("strYuAmount"));
       // final TableView tableView = new TableView();
        lvZongZhang.getColumns().clear();

        lvZongZhang.setItems(data);
        lvZongZhang.getColumns().addAll(idCol, taskIdCol, costNameCol, thisAmountCol, taskDateCol, employeeCol, operDateCol,yuErCol);

        apZongZhangBo.getChildren().remove(lvZongZhang);
        apZongZhangBo.getChildren().add(lvZongZhang);


        setKeMuController(keMuController);


        keMuController.showDetailAnchorPaneView(apZongZhangBo);

    }

之所以将科目层级和科目账薄类型的判断下移到策略实现类中,通过策略路由的方式去处理,为了在主界面控制器中增加新的策略时减少或没有代码的修改,虽然你增加了一点点代码,换来了主界面程序的扩展性,这可以根据自己需要决定,你认为直接在主界面中去判断然后确定策略类,这种效率更高,那也是可以的。眼下我追求的只是扩展性和健壮能性,相应的明细分类账的实现类如下:

java 复制代码
 /**
     * 显示总分类账

     * @return 显示面板
     */
    @Override
    public void showZhangBo(KeMu showZongZhangKeMu, KeMuController keMuController) throws IOException {
        // 使用 Context 来查看当它改变策略 Strategy 时的行为变化。
        if (showZongZhangKeMu != null && showZongZhangKeMu.getKeMuLevel().equals("1"))        //总分类账
        {
            keMuController.setStrategyShowZhangBen(new ZhangBenController());
            keMuController.getStrategyShowZhangBen().showZhangBo(showZongZhangKeMu,keMuController);
            return;
        }
       else if (showZongZhangKeMu != null && showZongZhangKeMu.getKeMuLevel().equals("2")) {
            keMuController.setStrategyShowZhangBen(new MingXiZhangController());
            showZongZhangKeMu = keMuController.convertChooseToParentKeMu(showZongZhangKeMu);


        }

        FXMLLoader loader2 = new FXMLLoader();
        InputStream in = MingXiZhangController.class.getResourceAsStream("/zhangBen/mingXiZhang.fxml");
        loader2.setBuilderFactory(new JavaFXBuilderFactory());
        loader2.setLocation(MingXiZhangController.class.getResource("/zhangBen/mingXiZhang.fxml"));

        AnchorPane page;
        try {
            page = (AnchorPane) loader2.load(in);
            keMuController.setStrategyShowZhangBen(loader2.getController());
        } finally {
            in.close();
        }

        /**
         * 控制器自转移
         */
        lbeZhangbBoName=((MingXiZhangController)keMuController.getStrategyShowZhangBen()).getLbeZhangbBoName();

        apZongZhangBo=((MingXiZhangController)keMuController.getStrategyShowZhangBen()).apZongZhangBo;
        lvMingXiZhang=((MingXiZhangController)keMuController.getStrategyShowZhangBen()).lvMingXiZhang;
        apMingXiZhang=((MingXiZhangController)keMuController.getStrategyShowZhangBen()).apMingXiZhang;


        setShowKeMu(showZongZhangKeMu);

        lbeZhangbBoName.setText(showKeMu.getKeMuName()+"明细账");


        List<MingXiZhang> listData= getDataFromSpiMingXiZhang(showKeMu.getStrDbId());
        data = FXCollections.observableArrayList(listData);
        //给表格加上行数 2022-08-25
        TableColumn idCol = new TableColumn();
        idCol.setText("日期");
        idCol.setCellValueFactory(new PropertyValueFactory("recordDate"));
      //  idCol.setVisible(false);

        TableColumn taskIdCol = new TableColumn();
        taskIdCol.setText("凭证号数");
        taskIdCol.setCellValueFactory(new PropertyValueFactory("strPingZhengNo"));
        TableColumn costNameCol = new TableColumn();
        costNameCol.setText("摘要");
        costNameCol.setCellValueFactory(new PropertyValueFactory("strZhaiYao"));
      
        TableColumn taskDateCol = new TableColumn();
        taskDateCol.setText("借方");
        taskDateCol.setMinWidth(200);
        taskDateCol.setCellValueFactory(new PropertyValueFactory("strJieFangAmount"));
        TableColumn daiFangCol = new TableColumn();
        daiFangCol.setText("贷方");
        daiFangCol.setMinWidth(200);
        daiFangCol.setCellValueFactory(new PropertyValueFactory("strDaiFangAmount"));
        TableColumn directCol = new TableColumn();
        directCol.setText("借或贷");
        directCol.setMinWidth(20);
        directCol.setCellValueFactory(new PropertyValueFactory("strAmountDirect"));
        TableColumn yuErCol = new TableColumn();
        yuErCol.setText("余额");
        yuErCol.setMinWidth(200);
        yuErCol.setCellValueFactory(new PropertyValueFactory("strYuAmount"));
        TableColumn[] AmountCol = new TableColumn[13];
        for(int i=0;i<13;i++){
            AmountCol[i]=new TableColumn();
            AmountCol[i].setText("金额分析"+String.valueOf(i+1));
            AmountCol[i].setMinWidth(200);
            AmountCol[i].setCellValueFactory(new PropertyValueFactory("amountFenXi"+String.valueOf(i+1)));
        }
        
       
       // final TableView tableView = new TableView();
        lvMingXiZhang.getColumns().clear();

        lvMingXiZhang.setItems(data);
        lvMingXiZhang.getColumns().addAll(idCol, taskIdCol, costNameCol, taskDateCol, daiFangCol, directCol,yuErCol);
        for (int i=0;i<AmountCol.length;i++){
            lvMingXiZhang.getColumns().add(AmountCol[i]);

        }

        apZongZhangBo.getChildren().remove(lvMingXiZhang);
        apZongZhangBo.getChildren().add(lvMingXiZhang);


       setKeMuController(keMuController);


        keMuController.showDetailAnchorPaneView(apZongZhangBo);



    }

至此,基本功能完成。

策略模式环境角色的客户端调用

这儿策略模式环境角色的特别之处在于它本身可能是通过FXML文件加载进去的类,大概率情况如下,所以我们不用在意从构造方法中去注入策略接口去赋值,通过get和set方法是最佳途径,这儿的代码就比较简单了,不过也要注意捕捉异常,代码如下:

java 复制代码
  @Override
            public void changed(ObservableValue<? extends TreeItem<KeMu>> observable, TreeItem<KeMu> oldValue, TreeItem<KeMu> newValue) {
                System.out.println("选择的新值是:" + newValue.getValue());
                KeMu chooseKeMu = newValue.getValue();
                try {
                    keMuController.getStrategyShowZhangBen().showZhangBo(chooseKeMu, keMuController);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

完成后,运行程序,效果如下图。至此,账薄的基本显示功能完成了,这只是相当于买回来两个账薄,价值也就是二三十无人民币,大量的工作才刚刚开始,让我们逐笔开始记录吧。

相关推荐
harder3211 天前
Swift 面向协议编程的 RMP 模式
开发语言·ios·mvc·swift·策略模式
skywalk81632 天前
esxi8 虚拟机中怎么安装mac os(纯AI回答,未实践)
策略模式·esxi
廖圣平2 天前
从零开始,福袋直播间脚本研究【八】《策略模式》
开发语言·python·bash·策略模式
爱学习 爱分享6 天前
简单工厂模式和策略模式的区别
简单工厂模式·策略模式
xcntime9 天前
Python中print函数如何实现不换行输出?
策略模式
青春易逝丶10 天前
策略模式
java·开发语言·策略模式
sg_knight10 天前
设计模式实战:策略模式(Strategy)
java·开发语言·python·设计模式·重构·架构·策略模式
liangshanbo121510 天前
[特殊字符] macOS 上的 zoxide:智能目录跳转终极指南
macos·策略模式
Rabbit_QL12 天前
【Warp+Claude】任务完成自动通知(macOS + Warp 版)
macos·策略模式
Sahadev_13 天前
macOS 解决 AirDrop 传输应用“已损坏“问题,以sublime为例
macos·策略模式·sublime text