November 10, 2020

Табличный метод

Табличный метод — это схема, позволяющая искать информацию в таблице, а не использовать для этого логические выражения, такие как if и case. Практически все, что вы можете выбирать посредством логических операторов, можно выбирать, применяя таблицы. В простых случаях логические выражения проще и понятней. Но при усложнении логических построений таблицы становятся все привлекательнее.


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

    if (month == 1) days = 31;
    else if (month == 2) days = 28;
    else if (month == 3) days = 31;
    else if (month == 4) days = 30;
    else if (month == 5) days = 31;
    else if (month == 6) days = 30;
    else if (month == 7) days = 31;
    else if (month == 8) days = 31;
    else if (month == 9) days = 30;
    else if (month == 10) days = 31;
    else if (month == 11) days = 30;
    else if (month == 12) days = 31;

Более простой и удобный для модификации способ выполнения тех же самых действий — разместить данные в таблице (в данном случае одномерном массиве):

    int daysPerMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    days = daysPerMonth[month-1];

Определение количества дней в месяце — удобный пример, так как переменную
month можно использовать для поиска записи в таблице.


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

if ( gender == Gender.Female ) {
    if ( maritalStatus == MaritalStatus.Single ) {
        if ( smokingStatus == SmokingStatus.NonSmoking ) {
            if ( age < 18 ) {
                rate = 200.00;
            }
            else if ( age == 18 ) {
                rate = 250.00;
            }
            else if ( age == 19 ) {
                rate = 300.00;
            }
            ...
            else if ( 65 < age ) {
                rate = 450.00;
            }
        else {
            if ( age < 18 ) {
                rate = 250.00;
            }
            else if ( age == 18 ) {
                rate = 300.00;
            }
            else if ( age == 19 ) {
                rate = 350.00;
            }
            ...
            else if ( 65 < age ) {
                rate = 575.00;
            }
        }
    else if ( maritalStatus == MaritalStatus.Married )
    ...
}

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

Вы можете сказать: «Да, но почему вы проверяете каждый возраст? Почему бы не поместить ставку для каждого возраста в массив?» Хороший вопрос, и одним из очевидных усовершенствований будет размещение ставок для каждого возраста в отдельных массивах.
Однако лучшее решение — создать массив ставок не только для каждого возраста, но вообще для всех факторов.

enum SmokingStatus{
    Smoking,
    NonSmoking
};
enum Gender{
    Male,
    Female
};
enum MaritalStatus{
    Single,
    Married
};
const int max_age = 100;

int main()
{
    double rateTable[2][2][2][max_age];
    // заполнение массива rateTeable
    
    double rate = rateTable[Smoking][Male][Married][43];
}

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


При применении табличных методов перед вами стоят два основных вопроса. Во-первых, вам надо решить, как будет выполняться поиск записей в таблице. Вы можете использовать какие-либо данные для прямого доступа к таблице. Так, если вам нужно систематизировать данные по месяцам, то выбор ключа для таблицы месяцев очевиден. Вы можете использовать массив с индексом от 1 до 12.

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

  • прямой доступ;
  • индексированный доступ;
  • ступенчатый доступ.

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