我有一个GiftCouponPayment类。它有一个可以经常更改的业务策略逻辑 - GetCouponValue()。目前的逻辑是“当优惠券号码小于2000时,优惠券价值应被视为零”。在未来的业务策略中,它可能会更改为“当优惠券发行日期小于1/1/2000时,优惠券价值应被视为零”。它可以根据公司的管理部门更改为任何此类策略。
我们如何使用策略模式重构GiftCouponPayment类,以便在GetCouponValue方法的策略时不需要更改类?
更新:在分析了责任后,我觉得“GiftCoupon”将是“GiftCouponPayment”课程的更好名称。
C#CODE
public int GetCouponValue()
{
int effectiveValue = -1;
if (CouponNumber < 2000)
{
effectiveValue = 0;
}
else
{
effectiveValue = CouponValue;
}
return effectiveValue;
}
阅读
答案 0 :(得分:3)
GiftCouponPayment类应将GiftCoupon传递给不同的策略类。所以你的战略界面( CouponValueStrategy )应该包含一个方法:
int getCouponValue(GiftCoupon giftCoupon)
由于实施 CouponValueStrategy 的每个具体策略都可以访问GiftCoupon,因此每个策略都可以实现基于优惠券号码或优惠券日期等的算法。
答案 1 :(得分: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
和CouponValue
的{{1}}类可能是有意义的,并从GetCouponValue()
引用此内容。
答案 2 :(得分: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;
}
}
你应该问自己的问题:现在是否有必要让它变得如此复杂?难道你不能让它尽可能简单地满足当前的需求,并在到期规则确实发生变化时重构它吗?
答案 3 :(得分: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。这更多地说明了你对“策略”模式的最初渴望 - 因为如果逻辑变得非常复杂,这将是有用的。