java - 跟踪复杂过程的部分结果的设计模式

标签 java algorithm oop design-patterns

我正面临一个我不知道如何在 中解决的编程问题面向对象 灵活 大大地。我想到了一些不好的解决方案,但我正在寻找一个好的解决方案。我用 Java 开发,所以我更喜欢 Java 的想法,但欢迎任何面向对象的想法。

我一直在寻找可以帮助我的想法、设计模式或一些算法,但我不知道我的问题是哪个术语或名称,所以我找不到任何线索。

问题:

总结:

我需要跟踪对实体集合进行不同更改的流程的部分结果。我需要它向用户报告表格报告中每个计算“步骤”的详细信息。而且我还需要将此集合保存在数据库中。

详情:

我维护的软件有一个类似于这个的实体:

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

它被分组在一个集合中,如下所示:
List<Salary> thisYearSalaries;

这组实体可以根据一些规则由一组“任务”修改:
  • 应用某种税(来自一组不同的税)
  • 计算金额的 future 值 ( More Info )
  • 折扣金额以保持在最大值以下
  • 等等...

  • 例如:
    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行数据,其余不关注)

    Report Example

    我的想法:

    为工资类 上的每个“部分结果”添加一个属性
    public class Salary {
        (...)
        private BigDecimal originalAmount;
        private BigDecimal amountAfterFirstTax;
        private BigDecimal amountAfterMaximumRestriction;
        (...)
    }
    

    问题:
  • “步”不是一成不变的,也许明天一个“步”变了,新的出现了,或者一些步的“意义”发生了变化。在这种情况下,我将需要过多地重构代码。
  • 一些“步骤”可以重复,那么,我如何告诉“方法”哪个属性必须“设置”计算结果?

  • 向 Salary 类添加一个 HashMap,我可以在其中放置部分结果,并将“键”传递给“步骤”方法,它必须在其中放置部分结果
    public class Salary {
        (...)
        HashMap<String, BigDecimal> partialResults;
        (...)
    }
    

    问题:
  • 在某些地方,我需要将 HashMap 填充到 JPA 实体以将其保存在我的数据库中
  • 如果另一个开发人员更改了 key 的名称(无论出于何种原因),属性的“填充”可能会被破坏

  • 最后说明:我的应用程序中还有其他“类似”实体的其他类似情况,所以如果我们能找到一个通用的解决方案,那就太好了:D

    编辑:关于如何对数据建模以将其持久化的新疑问

    所有的想法都是相似的,而且非常有用。所有这些都与命令模式有关,我认为这是很好的解决方案。但是现在我又有了一些新的疑惑:

    有了更高级别的抽象,我的应用程序会执行以下操作:
  • 用户输入工资列表
  • 该应用程序通过不同的“步骤”处理这些工资
  • 使用 LAST 工资金额计算平均值并继续其他计算
  • 经过一些屏幕和一些处理后,我会向用户显示一份报告,其中包含最终工资金额以及所有中间步骤。然后我保存这些中间信息用于审计目的

  • 这样,第二步就基本解决了。我会使用类似命令模式的东西。我现在的问题是如何对数据建模以将其保存在关系数据库中。因为,除了每个操作的部分“结果”之外,还有更多的信息不需要向用户展示,但我需要将其存储在数据库中。

    我的想法是这样的:

    薪资 table :
    id
    date // The date of the Salary
    finalAmount // The final amount after all the calculations ends
    

    部分结果 table :
    id
    salaryId // The id of the salary which this element represent a partial result
    amount // Partial amount
    operationCode // Type of operation
    operationDescription 
    

    但问题是,我的“ future 值(value)”操作有以下信息作为输出:
  • future 值的日期
  • 用于更新值的系数
  • 部分金额

  • 但是“申请税”操作有不同的信息:
  • % 已应用税
  • 部分金额

  • 那么,如何为不同的操作保存不同的“输出”信息?

    最佳答案

    我会将您执行的“操作”编码为对象。您拥有数据,当您对其应用操作时,该操作就是一个对象。操作对象拥有它自己的一些信息(可能是起始值和结束值),并且它知道如何格式化该值以进行输出。

    当您开始时,您会看到这些操作的队列——每一个都略有不同(可能是不同的类,可能只是在创建时具有内部状态差异)。您将此队列与您的数据结合起来,并将数据从队列中的一个部分传递到下一个,或者您可以将其视为遍历队列并将每个操作应用于数据(您可能传入的数据)。

    完成后,每个操作对象都会记住它们所做操作的历史记录并知道如何对其进行格式化(例如,“扣除 %s 百分比的税款”)并且您的数据已更改为正确的值。

    这也可以为您提供“展开”,您可以在其中以相反的顺序应用模式以备份到以前的值(您在这里可能不感兴趣,但在某些情况下可能会很棒)。

    我相信这被称为“命令”模式。它在任何情况下都非常有用。

    另一件好事 - 可以使用数据或任意数量的源选择放入队列的操作组,从而在许多情况下无需更改代码即可调整计算。

    这些类将非常简单,例如:

    公共(public)课税操作
    {
    私有(private)双倍率;
    私有(private)双倍征税;

    公共(public)税务操作(双倍率)
    {
    this.rate=rate;
    }

    @覆盖
    公共(public)双getValue(双初始)
    {
    已征税金额 = 初始 * 费率;
    返回初始值 - 已征税金额;
    }

    @覆盖
    公共(public)字符串 getDescription()
    {
    return "应用了 "+rate+"的税,其中扣除了 "+amountTaxed
    }
    }

    这看起来真的很简单,而且确实如此,但有时简单的类做得最多。显然 getValue 操作不是您想要的,但是您应该能够看到如何使用该模式推导出您想要的内容。

    另请注意,“操作”可以做任何事情——例如,它对于线程处理非常有用(想象一下您的操作需要几秒钟或几分钟,您只需将它们的队列提交给处理器并让它们离开)。

    关于java - 跟踪复杂过程的部分结果的设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18797074/

    相关文章:

    algorithm - 加速维特比执行

    java - 我在这个 ArrayList 中做错了什么?

    java - 如何获取 hibernate 内部属性?

    java - 使用 Batik to SVG 将 SVG 转换为 PNG 时,Linux 和 OSX 之间的文本差异

    c - utf-8 字符串的最佳哈希是什么

    c++ - 我可以使用指针而不是引用 (&) 为抽象基类编写复制构造函数吗?

    java - 使用 NTLM 对 Sharepoint 使用 HttpClient 身份验证机制时出现 HTTP 403 Forbidden

    mysql - 基于投票从 1 到 5 的人气排名算法

    涉及静态方法的php抽象类和接口(interface)?

    python - Moose 与 Python 的 OO 系统相比如何?