стратегическая модель в C#

Я проносился в Голове Первые Шаблоны разработки (просто вошел недавно), и я читал о стратегической модели, и мне пришло в голову, что это мог бы быть отличный способ реализовать распространенный способ вычислить налоги и т.д. на все конкретные объекты, которые я использую на работе, но у меня был вопрос об этом.

Вот то, что я думал:

public interface ITax
{
    decimal ProvincialTaxRate { get; set; } // Yes, I'm Canadian :)
    decimal CalculateTax(decimal subtotal);
}

public SaskatchewanTax
{
    public decimal ProvincialTaxRate { get; set; }

    public SaskatchewanTax()
    {
        ProvincialTaxRate = new decimal(0.05f);
    }

    public decimal CalculateTax(subtotal)
    {
        return ProvincialTaxRate * subtotal + FederalTaxRate * subtotal;
    }
}

public OntarioTax
{
    public decimal ProvincialTaxRate { get; set; }

    public OntarioTax()
    {
        ProvincialTaxRate = new decimal(0.08f);
    }

    public decimal CalculateTax(decimal subtotal)
    {
        return ProvincialTaxRate * subtotal + FederalTaxRate * subtotal;
    }
}

Вы, возможно, заметили, что нет никакого объявления FederalTaxRate, и это - то, что я хотел спросить. Куда это должно пойти?

  • Передача его в конструктору для каждого конкретного ITax кажется избыточной и допускала бы неправильное поведение (все налоговые калькуляторы должны совместно использовать тот же самый уровень федерального налога).
  • Аналогично, создание члена ITax позволило бы им быть непоследовательными также.

Действительно ли все должны обложить налогом калькуляторы, наследовались некоторому другому классу, где он определяется статически, а также ITax?

public class TaxCalculator
{
    public static decimal FederalTaxRate = new decimal(0.05f);
}
10
задан Cœur 11 July 2019 в 15:05
поделиться

6 ответов

Я думаю, что это распространенный случай злоупотребления паттернами.

Если вы проверите свои две «стратегии», они делают ТОЧНО одно и то же. Единственное, что меняется, это ProvincialTaxRate.

Я бы оставил вещи СУХИМЫМИ и не использовал бы этот шаблон (или любой другой) чрезмерно, здесь вы получаете немного гибкости, но тогда у вас также есть 2 класса, которые не тяготят, и, вероятно, вам не понадобится такая гибкость.

Это часто встречается, когда вы изучаете новую технологию или проницательность, вы хотите применять ее везде (это происходит с каждым из нас), даже если это наносит вред читабельности и удобству сопровождения кода.

Мое мнение: не усложняйте

С уважением

РЕДАКТИРОВАТЬ (В ответ на комментарий автора моего ответа)

Я не пытался высмеивать тебя или кого-либо. Это распространенная ошибка, я делал это МНОГИЕ раз и выучил ее нелегко, не только с шаблонами, но и с модными фреймворками, серверами, новыми технологиями модных слов, и так далее.

Авторы книги сами предупреждают читатели не должны чрезмерно использовать шаблоны, и возражения в этом ответе явно указывают на что-то тоже.

Но если по какой-то причине вы все еще хотите реализовать шаблон, вот мое скромное мнение:

  • Сделайте суперкласс для обеих стратегий, этот суперкласс будет абстрактным и должен содержать значение общей скорости их дочерних стратегий (FederalTaxRate)

  • Унаследовать и реализовать абстрактный метод «Вычислить» в каждом подклассе (здесь вы увидите, что оба метода одинаковы, но давайте продолжим)

  • Постарайтесь сделать каждую конкретную стратегию неизменной, всегда отдавайте предпочтение неизменности, как говорит Джошуа Блох. Для этого, Вот пример с некоторым (псевдо) кодом, чтобы сделать решение немного более понятным

    http://pastie.org/441068

    Надеюсь, это поможет

    С уважением

22
ответ дан 3 December 2019 в 15:22
поделиться

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

Я не думаю, что это однозначно лучшее решение, но оно будет работать отлично. Шаблоны проектирования не должны мешать вашему здравому смыслу, и я думаю, что здравый смысл прекрасно решит эту проблему.

2
ответ дан 3 December 2019 в 15:22
поделиться

Возможно, вы захотите начать с этого кода и двигаться дальше:

public interface ITax
{
    decimal CalculateTax(decimal subtotal);
}

public class SaskatchewanTax : ITax
{
    private readonly decimal provincialTaxRate;
    private readonly decimal federalTaxRate;

    public SaskatchewanTax(decimal federalTaxRate)
    {
        provincialTaxRate = 0.05m;
        this.federalTaxRate = federalTaxRate;
    }

    public decimal CalculateTax(decimal subtotal)
    {
        return provincialTaxRate * subtotal + federalTaxRate * subtotal;
    }
}

public class OntarioTax : ITax
{
    private readonly decimal provincialTaxRate;
    private readonly decimal federalTaxRate;

    public OntarioTax(decimal federalTaxRate)
    {
        provincialTaxRate = 0.08m;
        this.federalTaxRate = federalTaxRate;
    }

    public decimal CalculateTax(decimal subtotal)
    {
        return provincialTaxRate * subtotal + federalTaxRate * subtotal;
    }
}

В этот момент может не быть Было бы целесообразно иметь два разных объекта стратегии, представляющих расчет налога, но с более реалистичной реализацией (я предполагаю, что расчет налога более сложен и варьируется в зависимости от провинции).

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

2
ответ дан 3 December 2019 в 15:22
поделиться

Почему бы вам не забыть об интерфейсах и просто использовать наследование для того, что вы можете:

public abstract class Tax
{
    protected decimal ProvincialTaxRate; // Yes, you are Canadian ;)
    public decimal CalculateTax(decimal subtotal)
    {
        return ProvincialTaxRate * subtotal + FederalTaxRate * subtotal;
    }
    decimal FederalTaxRate = new decimal(0.20f);
}

public class SaskatchewanTax : Tax
{
    public SaskatchewanTax()
    {
        base.ProvincialTaxRate = new decimal(0.05f);
    }

}

public class OntarioTax : Tax
{
    public OntarioTax()
    {
        base.ProvincialTaxRate = new decimal(0.08f);
    }

}

Если вам нужно интерфейс, просто реализуйте его в базовом классе и просто используйте производные классы для пользовательского поведения / поведения.

2
ответ дан 3 December 2019 в 15:22
поделиться

Несколько моментов:

  1. ProvincialTaxRate почти наверняка должен быть неизменным на уровне интерфейса (нет ] установить свойство ). Изменение налоговых ставок не кажется хорошей идеей, хотя это означает, что вы не можете использовать автоматические свойства в своей реализации.

  2. Если есть только один FederalTaxRate и это просто простое числовое значение Я думаю, что абстрактный базовый класс является безопасным подходом.

  3. Менее целесообразно: в зависимости от того, как работают налоги, можно утверждать, что CalculateTax зависит от FederalTaxRate , и поэтому это необходимо предоставляется в качестве параметра (возможно, существуют разные FederalTaxRates , и вы не хотите, чтобы CalculateTax знал о них).

Don ' Позвольте определению шаблона проектирования помешать хорошей идее. Это шаблоны, а не формулы. ;)


PS Я американец, поэтому, если канадские налоги на самом деле так просты, я надеюсь, что IRS возьмет страницу из вашей книги в следующем году!

1
ответ дан 3 December 2019 в 15:22
поделиться

Просто пища для размышлений - что плохого в том, чтобы поместить этот метод в соответствующий класс и просто вызвать его?

public decimal CalculateTax(decimal subtotal, decimal provincialTaxRate, decimal federalTaxRate) {
    return provincialTaxRate * subtotal + federalTaxRate * subtotal;
    }

Я понимаю, что вы захотите использовать другой провинциальный ставка для каждой провинции, но неужели это не должно быть жестко закодировано в реализации интерфейса?

0
ответ дан 3 December 2019 в 15:22
поделиться
Другие вопросы по тегам:

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