0

我有一个 GiftCouponPayment 课程。它有一个可以经常改变的商业策略逻辑——GetCouponValue()。目前的逻辑是“当Coupon Number小于2000时,coupon value应该被认为是0”。在未来的商业策略中,它可能会更改为“当优惠券发行日期小于 1/1/2000 时,优惠券价值应视为零”。它可以根据公司的管理部门更改为任何此类策略。

我们如何使用策略模式重构 GiftCouponPayment 类,以便在 GetCouponValue 方法的策略时不需要更改该类?

更新:分析职责后,我觉得“GiftCoupon”将是“GiftCouponPayment”类的更好名称。

在此处输入图像描述

C# 代码

    public int GetCouponValue()
    {
        int effectiveValue = -1;
        if (CouponNumber < 2000)
        {
            effectiveValue = 0;
        }
        else
        {
            effectiveValue = CouponValue;
        }

        return effectiveValue;
    }

阅读

  1. 策略模式 - 多种返回类型/值
4

4 回答 4

3

GiftCouponPayment 类应该将 GiftCoupon 传递给不同的策略类。所以你的策略接口(CouponValueStrategy)应该包含一个方法:

int getCouponValue(GiftCoupon giftCoupon)

由于每个实现CouponValueStrategy的具体策略都可以访问 GiftCoupon,因此每个都可以实现基于 Coupon number 或 Coupon date 等的算法。

于 2012-07-11T15:02:37.147 回答
3

您可以将“优惠券价值策略”注入优惠券对象本身并调用它来计算优惠券价值。在这种情况下,可以传入this保单,以便保单可以向优惠券询问其所需的属性(例如优惠券编号):

public interface ICouponValuePolicy
{
  int ComputeCouponValue(GiftCouponPayment couponPayment);
}

public class GiftCouponPayment
{
  public ICouponValuePolicy CouponValuePolicy {
    get;
    set;
  }

  public int GetCouponValue()
  {
    return CouponValuePolicy.ComputeCouponValue(this);
  }
}

此外,您似乎GiftCouponPayment真正负责两件事(付款和礼券)。提取一个GiftCoupon包含CouponNumber和的类CouponValueGetCouponValue()GiftCouponPayment.

于 2012-07-11T15:07:58.350 回答
2

当您的业务逻辑发生变化时,您的代码也必须随之更改,这很自然。

您也许可以选择将过期检测逻辑移动到规范类中:

    public class CouponIsExpiredBasedOnNumber : ICouponIsExpiredSpecification
    {

        public bool IsExpired( Coupon c )
        {
             if( c.CouponNumber < 2000 )
                 return true;
             else
                  return false;
        }
    }

    public class CouponIsExpiredBasedOnDate : ICouponIsExpiredSpecification
    {
       public readonly DateTime expirationDate = new DateTime (2000, 1, 1);

       public bool IsExpired( Coupon c )
        {
             if( c.Date < expirationDate )
                 return true;
             else
                  return false;
        }
    }

public class Coupon
{
     public int GetCouponValue()
     {
        ICouponIsExpiredSpecification expirationRule = GetExpirationRule();

        if( expirationRule.IsExpired(this) ) 
           return 0;
        else
           return this.Value;

     }
}

你应该问自己的问题:现在有必要让它变得如此复杂吗?你不能让它尽可能简单以满足当前的需求,然后在过期规则确实发生变化时重构它吗?

于 2012-07-11T15:07:28.290 回答
1

您希望动态的行为是优惠券计算 - 它可以取决于任何数量的东西:优惠券日期,优惠券号码等。我认为提供者模式更合适,注入一个计算优惠券的服务类价值。

其本质是将业务逻辑移到 GiftCouponPayment 类之外,并使用我将称为“CouponCalculator”的类来封装业务逻辑。这个类使用一个接口。

interface ICouponCalculator
{
    int Calculate (GiftCouponPayment payment);
}

public class CouponCalculator : ICouponCalculator
{
   public int Calculate (GiftCouponPayment payment)
   {
      if (payment.CouponNumber < 2000)
      {
         return 0;
      }
      else
      {
         return payment.CouponValue;
      }
   }
}

现在你有了这个接口和类,给 GiftCouponPayment 类添加一个属性,然后修改你原来的 GetCouponValue() 方法:

public class GiftCouponPayment
{
   public int CouponNumber;
   public int CouponValue;

   public ICouponCalculator Calculator { get; set; }

   public int GetCouponValue()
   {
      return Calculator.Calculate(this);
   }
}

当您构造 GiftCouponPayment 类时,您将分配 Calculator 属性:

var payment = new GiftCouponPayment() { Calculator = new CouponCalculator(); }
var val = payment.GetCouponValue(); // uses CouponCalculator class to get value

如果这似乎只是将计算逻辑移到 GiftCouponPayment 类之外的大量工作,那么,就是这样!但如果这是您的要求,它确实提供了几件事:

1. 您不需要更改 GiftCouponPayment 类来调整计算逻辑。

2. 您可以创建额外的实现 ICalculator 的类,以及一个工厂模式来决定在构造 GiftCouponPayment 时将哪个类注入。这更能说明您最初对“策略”模式的渴望——因为如果逻辑变得非常复杂,这将很有用。

于 2012-07-11T15:34:34.110 回答