13

オブジェクト指向柔軟な方法で解決する方法がわからないプログラミングの問題に直面しています。いくつかの悪い解決策を念頭に置いていますが、良い解決策を探しています。私は Java で開発しているので、Java のアイデアを好みますが、オブジェクト指向のアイデアは大歓迎です。

私は自分に役立つアイデア、設計パターン、または何らかのアルゴリズムを探していましたが、どの用語や名前が私の問題に与えられているのかわからないため、手がかりを見つけることができませんでした.

問題:

概要:

エンティティのコレクションにさまざまな変更を加えるプロセスの部分的な結果を追跡する必要があります。テーブルレポートの各計算「ステップ」の詳細をユーザーに報告するには、これが必要です。また、このコレクションをデータベースに永続化する必要があります。

詳細:

私が管理しているソフトウェアには、次のようなエンティティがあります。

public class Salary {
    private Date date;
    private BigDecimal amount;
}

次のように、コレクションにグループ化されます。

List<Salary> thisYearSalaries;

この一連のエンティティは、いくつかのルールに応じて、一連の「タスク」によって変更できます。

  • 特定の税金を適用する (さまざまな税金のセットから)
  • 金額の将来価値を計算します (詳細情報)
  • 金額を割引して上限を下回るようにする
  • 等...

例えば:

public void processSalaries(List<Salary> theSalaries) {
    applyTax(theSalaries, Taxes.TAX_TYPE_1);
    (...)
    getFutureValue(theSalaries, someFutureDate);
    (...)
    restrictToAMaximum(theSalaries, Maximum.MARRIED_MAXIMUM);
    (...)
    applyTax(theSalaries, TAXES.TAX_TYPE_3);
    (...)
}

public void applyTax(List<Salary> theSalaries, Tax taxToApply) {
    for(Salary aSalary : theSalaries) {
        aSalary.setAmount(calculateAmountWithTax(aSalary.getAmount(), taxToApply);
    }
}

(...)

私が必要とするのは、この給与のコレクションを処理し、金額を変更しますが、金額のすべての中間「状態」を保持して、次のような列を持つテーブルでユーザーに表示することです。

レポート の例: (質問はデータの最初の 4 行のみに関するもので、残りは気にしないでください)

レポートの例

私のアイデア:

Salary クラスの「部分的な結果」ごとに属性を追加します。

public class Salary {
    (...)
    private BigDecimal originalAmount;
    private BigDecimal amountAfterFirstTax;
    private BigDecimal amountAfterMaximumRestriction;
    (...)
}

問題:

  • 「ステップ」は厳密なものではありません。明日、1 つの「ステップ」が変更されるか、新しいステップが表示されるか、いくつかのステップの「意味」が変更される可能性があります。その場合、コードをリファクタリングしすぎる必要があります。
  • いくつかの「ステップ」は繰り返すことができるので、どの属性が計算結果を「設定」する必要があるかを「メソッド」にどのように伝えることができますか?

部分的な結果を配置できる Salary クラスに HashMap を追加し、部分的な結果を配置する必要がある「キー」を「ステップ」メソッドに渡します。

public class Salary {
    (...)
    HashMap<String, BigDecimal> partialResults;
    (...)
}

問題:

  • ある場所で、HashMap を JPA エンティティに入力してデータベースに保存する必要があります
  • 別の開発者が (何らかの理由で) キーの名前を変更した場合、属性の「入力」が壊れる可能性があります

最終的な注意:私のアプリケーションには、他の「類似の」エンティティで同様の状況が他にもあるため、これに対する一般的な解決策を見つけることができれば幸いです :D


編集:データをモデル化して永続化する方法についての新たな疑問

すべてのアイデアは似ており、非常に便利です。それらはすべてコマンド パターンに関連しており、優れたソリューションだと思います。しかし今、私はいくつかの新しい疑問を持っています:

より高いレベルの抽象化により、私のアプリケーションは次のようになります。

  1. ユーザーは給与のリストを入力します
  2. アプリは、さまざまな「ステップ」を通じてこの給与を処理します
  3. 最後の給与額を使用して平均を計算し、他の計算を続行します
  4. いくつかの画面といくつかの処理の後、最終的な給与額とすべての中間ステップを含むレポートをユーザーに表示します。そして、この中間情報を監査目的で保存します

というわけで、2段目はほぼ解決。コマンドパターンのようなものを使用します。私の問題は、データをモデル化してリレーショナル データベースに永続化する方法です。各操作の部分的な「結果」以外にも、ユーザーに表示する必要はないが、データベースに保存する必要がある情報があるためです。

私の考えは次のようなものです:

給与表:

id
date // The date of the Salary
finalAmount // The final amount after all the calculations ends

partialResultsテーブル:

id
salaryId // The id of the salary which this element represent a partial result
amount // Partial amount
operationCode // Type of operation
operationDescription 

しかし、問題は、私の「将来の価値」操作には、出力として次の情報があることです。

  • 将来価値の日付
  • 値の更新に使用される係数
  • 一部金額

ただし、「税を適用する」操作には異なる情報があります。

  • 適用される税率
  • 一部金額

では、操作ごとに異なる「出力」情報を保存するにはどうすればよいでしょうか。

4

4 に答える 4

1

SalaryReportRowの多くのオブジェクトで構成されるSalaryReportという名前のクラスを作成できます。

SalaryReportには、すべてのアルゴリズムを実行するメソッド名calculate () があります。SalaryReportRowは、ニーズに合わせてさまざまな種類の行に特化できます。

class SalaryReport {

    private List<SalaryReportRow> rows;
    private List<SalaryCalculator> calculators;

    private HashMap<SalaryCalculator,List<SalaryReportRow>> results;

    ...

    public float getResults() {

    }

    public void applyCalculators(){
        for(SalaryCalculator s : calculators){
            results.put(s,s.execute(rows));
        }
    }

    public void setSalaryCalculators(List<SalaryCalculator> calculators){
        this.calculators = calculators;
    }

    public float getCalculation(SalaryCalculator s){
            return results.get(s);
    }
    ...

}

税金を計算するときは、戦略パターンを使用してコードをより柔軟に維持できます。多くの戦略を組み合わせる必要がある場合は、複合パターンと戦略、または責任の連鎖と戦略を使用することもできます。

abstract class SalaryCalculator implements Calculator {

        //Order of children matters
    protected List<SalaryCalculator> children = new ArrayList<SalaryCalculator>;

    public List<SalaryReportRow> execute(List<SalaryReportRow> rows){

        List<SalaryReportRow> result_rows = new ArrayList<SalaryReportRow> (rows);

        for(SalaryCalculator s: children){
            result_rows = s.execute(result_rows);
        }

        return result_rows;
    }

}

class TaxCalculator extends SalaryCalculator {

    public List<SalaryReportRow> execute(List<SalaryReportRow> rows){
        List<SalaryReportRow> result_rows = super.execute(rows);

        //
    }

}


class MaxSalaryCalculator extends SalaryCalculator {

    public List<SalaryReportRow> execute(List<SalaryReportRow> rows){
        List<SalaryReportRow> result_rows = super.execute(rows);

        ...
    }

}

class MaxSalaryWithTaxCalculator extends SalaryCalculator {

    public MaxSalaryWithTaxCalculator() {
        children.add(new MaxSalaryCalculator());
        children.add(new TaxCalculator());
    }

    public List<SalaryReportRow> execute(List<SalaryReportRow> rows){
        List<SalaryReportRow> result_rows = super.execute(rows);

        ...
    }
}

そのため、SalaryReportにはsetSalaryCalculators(List)というメソッドが含まれます (一度に複数のアルゴリズムを使用することもできます)。ここで、List は適用されるすべての戦略を含むリストです。

SalaryReportRowsが増えます:

  1. 一つは税金。
  2. 稼いだお金のための 1 つ。
  3. ...

したがって、すべてのステップを簡単に計算できます。

ストレージ ハンドラーと通信するときは、オブジェクトの作成と保存を担当するインターフェイスでDAO パターンを使用することをお勧めします。

これが役立つことを願っています。:)

于 2013-09-14T00:54:17.607 に答える