3

有人可以给我设计如何分别维护所有硬编码值。

我目前正在使用一些设计模式,这些可以吗?为了更好地设计我的应用程序代码,我还能做些什么。

我使用的设计模式是(我的应用程序有多个屏幕类似的向导):

  1. 对用户可见的所有字符串使用 ResourceBundle(用于国际化)
  2. 使用属性文件保存特定屏幕的所有值,以便其他屏幕可以访问(这些值用于程序的内部目的,用户不可见)。我不断在程序中的各个位置加载这些属性以获取更新的值,例如,从第一个屏幕转到第二个屏幕(面板)以获取第二个屏幕中第一个屏幕的值。
  3. 我正在考虑使用资源包将日志消息外部化。

有没有更好的设计方法?与程序代码分开,A.“用户可见的消息”,B.日志消息,C.可用性值(屏幕尺寸,字体等),用户在屏幕中输入的值,目录/文件路径......

4

4 回答 4

2

你的 GUI 应该有一个完整的数据模型。该模型可以读取 I18n 资源文件和常规资源文件来填充模型的一部分。数据模型是一个或多个 Java 类,它们在应用程序运行时保存对应用程序很重要的数据。

例如,这是我创建的秒表 GUI。

在此处输入图像描述

这是与秒表 GUI 关联的数据模型类。

import java.util.ArrayList;
import java.util.List;

import javax.swing.table.DefaultTableModel;

public class StopwatchModel {

    protected boolean isSplitTime;

    protected long startTime;

    protected long endTime;

    protected DefaultTableModel tableModel;

    protected List<Long> splitTimes;

    protected String[] columnNames = {"", "Increment", "Cumulative"};

    public StopwatchModel() {
        this.splitTimes = new ArrayList<Long>();
        this.isSplitTime = false;
        this.startTime = 0;
        this.endTime = 0;
        setTableModel();
    }

    public void resetTimes() {
        this.splitTimes.clear();
        this.isSplitTime = false;
        this.startTime = 0;
        this.endTime = 0;
    }

    public boolean isSplitTime() {
        return isSplitTime;
    }

    public long getStartTime() {
        return startTime;
    }

    public long getEndTime() {
        return endTime;
    }

    public long getLastSplitTime() {
        int size = splitTimes.size();
        if (size < 1) {
            return getStartTime();
        } else {
            return splitTimes.get(size - 1);
        }
    }

    public long getPenultimateSplitTime() {
        int size = splitTimes.size();
        if (size < 2) {
            return getStartTime();
        } else {
            return splitTimes.get(size - 2);
        }
    }

    public DefaultTableModel getTableModel() {
        return tableModel;
    }

    public int getTableModelRowCount() {
        return tableModel.getRowCount();
    }

    public void clearTableModel() {
        tableModel.setRowCount(0);
    }

    public int addTableModelRow(long startTime, long previousSplitTime, 
            long currentSplitTime, int splitCount) {
        String[] row = new String[3];

        row[0] = "Split " + ++splitCount;
        row[1] = formatTime(previousSplitTime, currentSplitTime, false);
        row[2] = formatTime(startTime, currentSplitTime, false);

        tableModel.addRow(row);

        return splitCount;
    }

    public void setStartTime() {
        if (getStartTime() == 0L) {
            this.startTime = System.currentTimeMillis();
        } else {
            long currentTime = System.currentTimeMillis();
            int size = splitTimes.size();
            if (size > 0) {
                long splitTime = splitTimes.get(size - 1);
                splitTime = splitTime - getEndTime() + currentTime;
                splitTimes.set(size - 1, splitTime);
            }
            this.startTime = currentTime - getEndTime() + getStartTime();
        }
    }

    protected void setTableModel() {
        this.tableModel = new DefaultTableModel();
        this.tableModel.addColumn(columnNames[0]);
        this.tableModel.addColumn(columnNames[1]);
        this.tableModel.addColumn(columnNames[2]);
    }

    public void setSplitTime() {
        this.splitTimes.add(System.currentTimeMillis());
        isSplitTime = true;
    }

    public void setEndTime() {
        Long split = System.currentTimeMillis();
        if (isSplitTime) {
            this.splitTimes.add(split);
        }
        this.endTime = split;
    }

    public String formatTime(long startTime, long time, boolean isTenths) {
        long elapsedTime = time - startTime;

        int seconds = (int) (elapsedTime / 1000L);

        int fraction = (int) (elapsedTime - ((long) seconds * 1000L));
        fraction = (fraction + 5) / 10;
        if (fraction > 99) {
            fraction = 0;
        }
        if (isTenths) {
            fraction = (fraction + 5) / 10;
            if (fraction > 9) {
                fraction = 0;
            }
        }


        int hours = seconds / 3600;
        seconds -= hours * 3600;

        int minutes = seconds / 60;
        seconds -= minutes * 60;

        StringBuilder builder = new StringBuilder();

        builder.append(hours);
        builder.append(":");
        if (minutes < 10) builder.append("0");
        builder.append(minutes);
        builder.append(":");
        if (seconds < 10) builder.append("0");
        builder.append(seconds);
        builder.append(".");
        if ((!isTenths) && (fraction < 10)) builder.append("0");
        builder.append(fraction);

        return builder.toString();
    }

}

该模型还将包含让您从一个JPanel到另一个的瞬态数据JPanel。瞬态数据是只需要在短时间内存在的数据,通常只要 GUI 处于活动状态。退出 GUI 后不必保存它。

使用模型/视图来构建 GUI 的原因是关注点分离。应用程序的其余部分访问数据模型,而不是任何 GUI 组件。

于 2012-10-17T13:08:09.853 回答
2

我会查看Java Preferences API,它允许您存储系统范围的默认值、每个用户的默认值,并在没有配置值的情况下使用硬编码的默认值。

于 2012-10-17T11:48:03.017 回答
2

I18N 的资源包是完全正确的。属性文件做得很好,但如果您更改它们,您将不得不重新打包和重新部署。将其他项目放入数据库通常更灵活,因为您可以通过推送数据来更改应用程序,而无需重新打包和重新部署。

于 2012-10-17T11:49:28.887 回答
0

对于“可用性值”,我使用了单例模式。创建一个名为 Configuration 的类,然后创建一个Configuration.getConfig()调用私有构造函数的静态方法。您的程序需要的所有对象都可以存储为此类中的字段。构造函数使用首选项 API 加载值。我在最近的 SO 帖子中为此发布了一些示例代码。

将所有配置数据放在一个负责加载它的类中的优点是,现在您存储此数据的方法已从其余代码中抽象出来。如果您决定使用数据库或 ResourceBundle 进行存储,则只需更改配置。

于 2012-10-17T12:04:12.560 回答