C# C类设计,灵活的支付规则

C# C类设计,灵活的支付规则,c#,single-responsibility-principle,C#,Single Responsibility Principle,我目前正在为一个负责管理版税支付的系统建模。特许权使用费可以简单到: 向作者支付收入的15% 或者像以下两者一样复杂: 向作者B支付收入的15%,最多1000个销售数量,然后支付收入的12% 还应向作者支付每笔销售1.50美元,最多可销售1000个数量 或: 在第一笔1000美元的收入中,向作者C支付收入的15%,然后支付收入的12% 简言之,付款可以是每次售出的固定金额,也可以是收入的百分比。付款条件可基于销售数量或收入。我试图设计一个类(它与后台的数据库表密切对应),通过指定付款

我目前正在为一个负责管理版税支付的系统建模。特许权使用费可以简单到:

  • 向作者支付收入的15%
或者像以下两者一样复杂:

  • 向作者B支付收入的15%,最多1000个销售数量,然后支付收入的12%
  • 还应向作者支付每笔销售1.50美元,最多可销售1000个数量
或:

  • 在第一笔1000美元的收入中,向作者C支付收入的15%,然后支付收入的12%
简言之,付款可以是每次售出的固定金额,也可以是收入的百分比。付款条件可基于销售数量或收入。我试图设计一个类(它与后台的数据库表密切对应),通过指定付款范围和付款值的类型来包含所有这些灵活性。然而,我担心我可能试图让这门课做得太多,如果我们需要在未来适应更多的场景,可能会让自己陷入困境。我正在寻求其他设计方法的建议

public class PaymentRule
{
    // I'm not 100% comfortable with this, as this will
    // really be an Int32 value for quantity sold ranges
    public decimal RangeMinimum { get; set; }
    public decimal? RangeMaximum { get; set; }

    // This will always be a decimal value, but may represent
    // a dollar amount or percentage depending on the context
    public decimal PaymentValue { get; set; }

    // Specify a type for the range: QuantitySold or Revenue
    public string RangeType { get; set; }

    // Specify a type for the value: AmountPerEachSold or RevenuePercentage
    public decimal ValueType { get; set; }

    public decimal CalculateRoyaltyDue(int quantitySold, decimal revenue)
    {
        // ...
    }
}
如有任何建议,将不胜感激

2012年5月9日更新:

我应该提到的是,这些规则必须持久化到SQL Server数据库。

请查看-这罐复杂的规则规范正是它的设计初衷

在计算机编程中,规范模式是一种特殊的软件设计模式,通过使用布尔逻辑将业务规则链接在一起,可以重新组合业务规则

规范模式概述了可与其他业务规则组合的业务规则。在此模式中,业务逻辑单元从抽象聚合复合规范类继承其功能。复合规范类有一个名为issatifiedby的函数,它返回一个布尔值。实例化后,规范与其他规范“链接”,使新规范易于维护,但高度可定制的业务逻辑。此外,在实例化之后,业务逻辑可以通过方法调用或控制反转改变其状态,以便成为其他类(如持久性存储库)的委托


我会尝试构建某种流畅的接口,将扩展方法、linq表达式、方法chining和命名参数结合起来,可能是这样的:

var revenue = 12000;
var ruleA = Rules.PayAuthor(15).PercentOf(revenue)
var ruleB = Rules.PayAuthor(15).PercentOf(revenue).UpTo(soldUnits:1000).Then(12).PercentOf(revenue)

var royalltyA = Royallty.For(ruleA, whenSoldUnitsIs: 1500);
var royalltyB = Royallty.For(ruleB, whenSoldUnitsIs: 1500);

看起来LINQ处理了这个模式完成的所有事情。或者我没有抓住要点?你可能需要一个规则引擎。你正在编写系统,但一些非程序员会使用它。他如何将付款规则与作者联系起来?他需要能够自己扩展系统吗?用户界面由一个简单的下拉列表组成,或者用户会被DSL所困扰吗?还是简单的付款规则列表?是否会有一些边缘情况下,特定的实现似乎是合适的?@StefanHanke当前的用户界面相当紧密地受到这样一个假设的约束,即每个支付规则都有一个最小范围(即使最小值为0)和一个可选的最大范围。必须从下拉列表中选择范围类型(收入或销售数量)。必须指定支付值,并且必须从下拉列表中选择支付值类型(收入百分比或每销售一次的金额)。我已经更新了原始问题,以指示RangeMaximum属性的可选性质。可能会在某些地方保留付款规则,并且这个流畅的界面永远无法使用。我添加了持久性要求,因为我觉得它对建议的解决方案有重大影响。没错,我从未考虑过持久性方面。尽管如此,您仍然可以构建流畅的界面,在基础模型上设置属性,计算收入,然后保存对象。您将需要一些Tweek,但仍然可能。是的,提议的解决方案根本不起作用。