Существует ли хороший способ избежать неиспользованного параметра метода в некоторых подклассах при применении стратегической модели?

У меня есть следующий сценарий, где у меня есть различные виды алгоритмов продаж для вычисления продажной цены. 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;
    }
}
8
задан derdo 30 July 2010 в 23:33
поделиться

6 ответов

В основе шаблона стратегии лежит идея о том, что вызывающий код не знает вызываемую реализацию.

Если бы вы изменили параметры, используемые для каждой реализации, вы бы обнаружили, что не получаете всех преимуществ этого шаблона: вызывающему нужно было бы знать, какая реализация будет использоваться и как ее вызвать.

Я обычно передаю класс, содержащий супернабор информации (что-то вроде PricingInfo), который всегда заполняется одинаково (в идеале централизовано в коде), и единственная разница заключается в реализации стратегии. .

Одним из преимуществ является то, что я могу добавить свойство к моему классу PricingInfo, которое не было актуальным в прошлом (например, systemDiscount), и влияние на систему в целом не слишком велико.

6
ответ дан 5 December 2019 в 12:54
поделиться

На мой взгляд, не очень хороший. Я бы оставил это как есть. Вы можете использовать различные уловки, например params (с одним params double [] priceData) или IDynamicObject . Но лучше всего, если некоторые стратегии игнорируют дополнительный параметр.

0
ответ дан 5 December 2019 в 12:54
поделиться

Другой альтернативой является использование объекта параметров или Dictionary . Таким образом, вы можете объединить количество параметров для каждого метода и оставить место для дополнительных параметров, если в будущем произойдут изменения требований.

Единственным недостатком является то, что Dictionary может усложнить отслеживание параметров в вашем коде, тогда как объект параметров просто будет иметь все свойства, которые вы можете просматривать в вашем коде.

0
ответ дан 5 December 2019 в 12:54
поделиться

Нет. Это не лишний параметр; код, использующий SalesStrategy, не должен знать, какой конкретный класс он использует, поэтому сигнатура метода должна быть идентичной во всех производных классах.

5
ответ дан 5 December 2019 в 12:54
поделиться

Если вы используете 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); 
2
ответ дан 5 December 2019 в 12:54
поделиться

Хороший способ удалить нерелевантные параметры из интерфейса - передать эти параметры в конструкторы из подклассов. Итак, альтернативой для вашего дизайна может быть:

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;
        }
    }

В этой конструкции вы не загрязняете свой интерфейс конкретными данными из подклассов.

0
ответ дан 5 December 2019 в 12:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: