我有以下情况,我有不同类型的销售算法来计算销售价格。 FixedSaleStrategy不需要basePrice参数,而所有其他策略实现都需要它。有没有一种避免这种冗余参数的好方法?
public abstract class SalesStrategy
{
public abstract double GetPrice(double basePrice, double saleAmount);
}
public class AmountOffSale : SalesStrategy
{
public override double GetPrice(double basePrice, double salesAmount)
{
return basePrice - salesAmount;
}
}
public class FixedPriceSale : SalesStrategy
{
public override double GetPrice(double basePrice, double salesAmount)
{
return salesAmount;
}
}
答案 0 :(得分:6)
策略模式的核心是调用代码不知道被调用的实现。
如果您要更改每个实现使用的参数,您会发现您没有充分利用此模式:调用者需要知道将使用哪个实现以及如何调用它。
我倾向于传递一个包含超级信息集(类似于PricingInfo)的类,它总是以相同的方式填充(理想情况下集中在代码中),唯一的区别是策略的实现
其中一个好处是我可以在我的PricingInfo类中添加一个过去不相关的属性(例如systemDiscount),并且对整个系统的影响不是太大。
答案 1 :(得分:5)
没有。它不是一个冗余参数;使用SalesStrategy的代码不应该知道它正在使用哪个具体类,因此方法签名在所有派生类中必须相同。
答案 2 :(得分:2)
如果您使用的是c#4.0,则可以反转参数并使basePrice
可选,如下所示:
public abstract class SalesStrategy
{
public abstract double GetPrice(double saleAmount, double basePrice = 0d);
}
public class AmountOffSale : SalesStrategy
{
public override double GetPrice(double salesAmount, double basePrice)
{
return basePrice - salesAmount;
}
}
public class FixedPriceSale : SalesStrategy
{
public override double GetPrice(double salesAmount, double basePrice = 0d)
{
return salesAmount;
}
}
意味着可以做以下事情......
FixedPriceSale fixedPrice = new FixedPriceSale();
...
fixedPrice.GetPrice(salesAmount);
请注意,AmountOffSale
的{{1}}参数不是可选,这意味着以下内容无法编译:
basePrice
答案 3 :(得分:0)
在我看来,这不是一个好人。我会保持原样。您可以使用各种技巧,例如params(有一个参数double [] priceData)或IDynamicObject
。但最干净的只是让一些策略忽略额外的参数。
答案 4 :(得分:0)
从接口中删除不相关参数的好方法是在子类的构造函数中传递这些参数。因此,您的设计的另一种选择是:
public interface SalesStrategy
{
double CalculatePrice(double basePrice);
}
public class FixedPriceSale : SalesStrategy
{
public double CalculatePrice(double basePrice)
{
return basePrice;
}
}
public class AmountOffSale : SalesStrategy
{
public double SalesAmount { get; set; }
public AmountOffSale(double salesAmount)
{
this.SalesAmount = salesAmount;
}
public double CalculatePrice(double basePrice)
{
return basePrice - SalesAmount;
}
}
在该构造中,您不会使用子类中的特定数据污染您的接口。
答案 5 :(得分:0)
另一种方法是使用参数对象或Dictionary<string, object>
。通过这种方式,您可以合并每种方法的参数数量,并在将来需求发生变化时为其他参数留出空间。
一个缺点是Dictionary<string, object>
可以使代码中的参数更难跟踪,而参数对象只会包含您可以在代码中查看的所有属性。