【问题标题】:How to name variables that represent thresholds or limits?如何命名代表阈值或限制的变量?
【发布时间】:2009-09-29 21:10:12
【问题描述】:

例如,假设我们有一个票务系统可以配置为以正常价格提供门票,但是一旦您在活动开始的X 小时内,您就会以不同的价格提供门票(可能会打折或增加)。我们将其称为“抢购价”。此外,一旦您在活动的Y 小时内,您就可以以另一个价格提供它们。我们将其称为“紧急价格”。

表示此配置信息的类可能如下所示:

public class RushTicketPolicy {

    private int rushHours;
    private int emergencyHours;

    public RushTicketPolicy(int rushHours, int emergencyHours) {
        this.rushHours      = rushHours;
        this.emergencyHours = emergencyHours;
    }

    public int RushHours      { get { return this.rushHours; } }
    public int EmergencyHours { get { return this.emergencyHours; } }
}

我发现很难为这些变量(和属性)想出足够表达和完整的名称,而不参考使用它们的代码,也不需要额外的推断。

也就是说,没有看过其余代码或对其业务需求一无所知的人应该能够查看变量名称并理解:

  • 在活动前几个小时X 开始抢购。
  • 紧急销售在活动前几个小时开始Y,包括在内。

有哪些名字可以做到这一点?

【问题讨论】:

  • 我的一位同事提出了一个非常有趣的建议。我试图让他发布它,但要点是清楚地命名这个变量非常困难,因为该类不引用事件,这是模型的关键元素。试图将其硬塞到变量名中不可避免地会导致混淆。因此,他建议使用类似TicketingPeriodStart 类的东西,该类带有hoursBeforeEvent 变量和(至关重要的)一个更符合我们对数据的看法的公共方法:GetTicketingPeriodStartDate(DateTime eventDate)
  • (续)这将涉及将课程从我的问题分成两个实例(一个代表紧急票务的开始,另一个代表紧急票务的开始)。当然,这些配置设置可能存在于数据库中的单个表中,因此它可能只是推迟了这个问题......如何命名代表阈值或限制的

标签: language-agnostic naming


【解决方案1】:
public class SalesPeriodStartRule {

    private int mHoursBeforeEvent = 0;

    public SalesPeriodStartRule(int hoursBeforeEvent) {
        mHours = hoursBeforeEvent;
    }
    public DateTime GetEffectiveDate(DateTime showDate) {
        return showDate.AddHours(-mHoursBeforeEvent);
    }
}

public class PricingPolicy {
    private SalesPeriodStartRule mRushRule;
    private SalesPeriodStartRule mEmergencyRule;

    public PricingPolicy(SalesPeriodStartRule rushRule, SalesPeriodStartRule emergencyRule) {
        mRushRule      = rushRule;
        mEmergencyRule = emergencyRule;
    }
    public string GetPriceCategory(DateTime purchaseDate, DateTime showDate) {
        if (purchaseDate > mEmergencyRule.GetEffectiveDate(showDate)) {
            return "Emergency";
        }
        else if (purchaseDate > mRushRule.GetEffectiveDate(showDate)) {
            return "Rush";
        }
        else {
            return "Standard";
        }
    }
}

【讨论】:

  • 这是我上面提到的同事的 - 我只是编辑了他的代码以适应原始示例。
  • 虽然我的一部分人仍然坚持使用可以表达最初陈述的整个概念的变量名称,但重构为两个类并封装生效日期计算确实澄清了这一点,所以我接受直到有人想出了一个恰到好处的变量名
【解决方案2】:

我喜欢冗长:

DiscountThresholdInSeconds

根据您的编辑 #1:

如果你有一个类“票”,我会简单地给它一个折扣集合:

public class Ticket { private List <Discount> m_availableDiscounts = new List<Discount>(); private decimal m_basePrice = 0m; private DateTime m_showTime; public Ticket(DateTime showTime) { m_showTime = showTime; } public List<Discount> Discounts { get { return m_availableDiscounts; } } public decimal BasePrice { get { return m_basePrice; } set { m_basePrice = value; } } public DateTime ShowTime { get { return m_showTime; } } public decimal CalculatePrice(int quantity) { //Apply discounts here... } } public class Discount { private int m_thresholdInSeconds = 0; private decimal m_percentOff = 0m; private decimal m_flatAmountOff = 0m; public Discount(int thresholdInSeconds, decimal percentOff, decimal flatAmountOff) { m_thresholdInSeconds = thresholdInSeconds; m_percentOff = percentOff; m_flatAmountOff = flatAmountOff; } public int ThresholdInSeconds { get { return m_thresholdInSeconds; } } public decimal PercentOff { get { return m_percentOff; } } public decimal FlatAmountOff { get { return m_flatAmountOff; } } }

根据问题编辑 #2 编辑 #2

您列出的代码与我提供的代码之间的区别在于,您的代码只允许两个不同的折扣期,而我的代码支持分层模型。如果我们真的在这里谈论门票,请将其视为时间线:

现在---------------------------------------------- ---------------------------------------放映时间

在此期间的任何时候,您都可能超过了有资格获得折扣的阈值(检查点、边界等)。

------------|------现在------------|-------------- ----|---------------|---|---演出时间

由于 ShowTime 是此时间线中的稳定信息,因此您需要捕获与 showtime 的“距离”和适用的折扣。与 ShowTime 的“距离”是跨越的门槛。

【讨论】:

  • 我也喜欢冗长 - 但考虑到变量名称,折扣是在达到阈值之前还是之后适用?
  • 我的阅读将在它满足之后。如果是之前,我会称之为 DiscountExpirationThresholdInSeconds。
  • 嗯,我对可以直接表达这一点的变量名感兴趣,这样它就没有歧义了。
  • 我非常感谢这里的讨论,我并不是要诱饵和切换编辑!实际上,在可能的情况下,您提出的类设计可能会更好(如果阈值信息来自与折扣信息不同的来源,则不会如此),但变量名称仍然存在我正在尝试的问题解决:thresholdInSeconds 没有表达阈值与(事件)的关系,也没有描述应该在间隔之前还是之后应用折扣。
  • 这对我来说似乎是过早的概括。他的方法支持 0,1 或 2 个折扣期(您可以将折扣设置为 0。)如果不太可能有超过 2 个折扣期,为什么要编写更长、不太清晰的代码来支持不会出现的功能需要吗?
【解决方案3】:

将其命名为它所代表的... :D

RushTicketPolicyValidityIntervalLength

好的,班级已经有了部分信息。那么这个呢?

ValidityIntervalLength

或类似的东西。

【讨论】:

  • interval 这个词很可能是解决方案的一部分,但这并不表示间隔适用的时间段。
【解决方案4】:

也许您可以使用fluent interface 使 API 更具表现力。 考虑以下几点:

public class Test
{
    public string TestPolicies()
    {
        int year = 2010;
        int month = 11;
        int day = 3;
        int hour = 15;
        int minute = 30;
        int second = 0;

        DateTime eventDateTime = new DateTime(year, month, day, hour, minute, second);

        IConfiguredTicketPolicy emergencyTicketPolicy = new TicketPolicy().Starts(2).HoursBefore(eventDateTime).Inclusive();
        IConfiguredTicketPolicy rushTicketPolicy      = new TicketPolicy().Starts(4).HoursBefore(eventDateTime).Inclusive();

        DateTime now = DateTime.Now;

        if (emergencyTicketPolicy.IsEffectiveAsOf(now))
        {
            return "Emergency";
        }
        else if (rushTicketPolicy.IsEffectiveAsOf(now))
        {
            return "Rush";
        }
        else
        {
            return "Standard";
        }            
    }
}

TicketPolicy 类的实现看起来像这样:

    public class TicketPolicy : IConfigurePolicySalesStart, IConfigurePolicyHoursBefore, IConfigurePolicyInclusive, IConfiguredTicketPolicy
{
    private int mHours;
    public IConfigurePolicyHoursBefore Starts(int hours)
    {
        TicketPolicy clone = this.Clone();
        clone.mHours = hours;
        return clone;
    }

    private DateTime mEventDateTime;
    public IConfigurePolicyInclusive HoursBefore(DateTime eventDateTime)
    {
        TicketPolicy clone = this.Clone();
        clone.mEventDateTime = eventDateTime;
        return clone;
    }

    private bool mInclusive = false;
    public IConfiguredTicketPolicy Inclusive()
    {
        TicketPolicy clone = this.Clone();
        clone.mInclusive = true;
        return clone;
    }

    public bool IsEffectiveAsOf(DateTime now)
    {
        DateTime effectiveDate = mEventDateTime.AddHours(-1*this.mHours);
        if (!this.mInclusive)
        {
            effectiveDate = effectiveDate.AddTicks(1);
        }

        return effectiveDate.CompareTo(now) < 0;
    }
    public TicketPolicy Clone()
    {
        TicketPolicy clone = new TicketPolicy();
        clone.Starts(this.mHours);
        clone.HoursBefore(this.mEventDateTime);
        if (this.mInclusive)
        {
            clone.Inclusive();
        }
        return clone;
    }
}  

这些接口用于帮助智能感知通过 API 导航用户,可能不是必需的。它们可能看起来像这样:

public interface IConfigurePolicySalesStart
 {
     IConfigurePolicyHoursBefore Starts(int hours);
 }

 public interface IConfigurePolicyHoursBefore
 {
     IConfigurePolicyInclusive HoursBefore(DateTime eventDateTime);
 }

 public interface IConfigurePolicyInclusive
 {
     IConfiguredTicketPolicy Inclusive();
 }

 public interface IConfiguredTicketPolicy
 {
     bool IsEffectiveAsOf(DateTime now); 
 }

【讨论】:

  • 编辑帖子以实现 IsEffectiveAsOf(DateTime.Now);
  • 想更多关于原始问题,像 NumberOfDaysBeforeEventLatePeriodBeginsInclusive 这样的名称怎么样?
猜你喜欢
  • 2010-09-16
  • 2020-04-22
  • 2015-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多