9

我有以下场景,我有不同种类的销售算法来计算销售价格。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;
    }
}
4

6 回答 6

6

策略模式的核心是调用代码不知道被调用的实现。

如果您要更改每个实现使用的参数,您会发现您没有获得这种模式的全部好处:调用者需要知道将使用哪个实现以及如何调用它。

我倾向于传递一个包含超集信息的类(例如 PricingInfo),它总是以相同的方式填充(理想情况下集中在代码中),唯一的区别是策略的实现。

好处之一是我可以向我的 PricingInfo 类添加一个过去不相关的属性(比如 systemDiscount),并且对整个系统的影响不会太大。

于 2010-07-31T01:21:08.757 回答
5

不,这不是多余的参数;使用 SalesStrategy 的代码不应该知道它正在使用哪个具体类,因此方法签名在所有派生类中必须相同。

于 2010-07-30T23:43:00.367 回答
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'basePrice参数不是可选的,这意味着以下将不会编译:

AmountOffSale amountOffSale = new AmountOffSale();
...
// No overload for method 'GetPrice' takes 1 arguments
amountOffSale.GetPrice(salesAmount); 
于 2010-07-30T23:42:55.907 回答
0

在我看来,这不是一个好人。我会保持原样。您可以使用各种技巧,例如params(有一个参数 double[] priceData)或IDynamicObject. 但最干净的就是让一些策略忽略额外的参数。

于 2010-07-30T23:39:57.830 回答
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;
        }
    }

在这种结构中,您不会用来自子类的特定数据污染您的接口。

于 2010-07-31T01:06:30.003 回答
0

另一种选择是使用参数对象或Dictionary<string, object>. 通过这种方式,您可以合并每种方法的参数数量,并在未来需求发生变化时为其他参数留出空间。

一个缺点是,aDictionary<string, object>会使在代码中跟踪参数变得更加困难,因为参数对象将仅具有您可以在代码中查看的所有属性。

于 2010-07-31T01:16:15.600 回答