3

誰かが私にすべてのハードコードされた値を個別に維持する方法の設計を教えてもらえますか?

現在、いくつかのデザインパターンを使用していますが、これらは問題ありませんか?また、アプリケーションコードをより適切に設計するためにできることは他にありますか。

私が使用する設計パターンは次のとおりです(私のアプリケーションには、ウィザードに似た複数の画面があります)。

  1. ユーザーに表示されるすべての文字列にResourceBundleを使用する(国際化の場合)
  2. プロパティファイルを使用して特定の画面のすべての値を保存し、他の画面からアクセスできるようにします(これらの値はプログラムの内部目的であり、ユーザーには表示されません)。これらのプロパティをさまざまな場所でプログラムに継続的にロードして、更新された値を取得します。たとえば、最初の画面から2番目の画面(パネル)に移動して、2番目の画面で最初の画面の値を取得します。
  3. リソースバンドルを使用してログメッセージを外部化することを考えています。

より良い設計アプローチはありますか?プログラムコードから分離するには、A。「ユーザーに表示されるメッセージ」、B。ログメッセージ、C。ユーザビリティ値(画面サイズ、フォントなど)、ユーザーが画面に入力した値、ディレクトリ/ファイルパス...

4

4 に答える 4

2

GUI には完全なデータ モデルが必要です。このモデルは、I18n リソース ファイルと通常のリソース ファイルを読み取って、モデルの一部を設定できます。データ モデルは、アプリケーションの実行中にアプリケーションにとって重要なデータを保持する 1 つ以上の 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 に答える