Метод извлечения является наиболее часто используемым методом рефакторинга. Он реорганизует код для лучшего повторного использования и удобочитаемости.

Ах! хорошо. Давайте продолжим.

Используйте метод извлечения в следующих случаях —

Когда ваш класс содержит длинный метод.

Длинный метод делает несколько вещей и не считается связным. Метод более 10 строк можно считать максимально длинным.

Перед применением метода извлечения:

См. ниже основной метод. Он делает больше, чем одну вещь.

using System;
using System.Collections.Generic;

namespace NMart.Billing
{
    internal class NMartStore
    {
        private static Dictionary<string, int> CategoryGstRatesInPercentage = new Dictionary<string, int>();
        private static Dictionary<string, string> ItemsCategoryMapping = new Dictionary<string, string>();

        private static void Main()
        {
            CategoryGstRatesInPercentage.Add("Food-grains", 0);
            CategoryGstRatesInPercentage.Add("Furniture", 5);
            CategoryGstRatesInPercentage.Add("Electronics", 18);
            CategoryGstRatesInPercentage.Add("Cosmetics", 28);

            ItemsCategoryMapping.Add("Rice", "Food-grains");
            ItemsCategoryMapping.Add("Wheat", "Food-grains");
            ItemsCategoryMapping.Add("Sofa", "Furniture");
            ItemsCategoryMapping.Add("Chairs", "Furniture");
            ItemsCategoryMapping.Add("TV", "Electronics");
            ItemsCategoryMapping.Add("Mobile", "Electronics");
            ItemsCategoryMapping.Add("Shampoo", "Cosmetics");
            ItemsCategoryMapping.Add("Perfume", "Cosmetics");

            Console.WriteLine("Welcome to NMart store");
            Console.WriteLine("***************************");

            Console.Write("Enter name of item: ");
            string itemName = Console.ReadLine();
            Console.Write("Enter quantity of item: ");
            int itemQuantity = int.Parse(Console.ReadLine());
            Console.Write("Enter rate per product item: ");
            int ratePerUnitItem = int.Parse(Console.ReadLine());

            string categoryName = "";

            foreach (var item in ItemsCategoryMapping)
            {
                if (item.Key == itemName)
                {
                    categoryName = item.Value;
                    break;
                }
            }

            int gstPercentageForItem = 0;

            foreach (var categoryGstRate in CategoryGstRatesInPercentage)
            {
                if (categoryGstRate.Key == categoryName)
                {
                    gstPercentageForItem = categoryGstRate.Value;
                    break;
                }
            }

            double finalPrice = itemQuantity * (ratePerUnitItem + ratePerUnitItem * gstPercentageForItem / 100.0);

            string output = "*******************************************\n" +
                "Billing Details for " + itemName + ":\n" +
                "*******************************************\n" +
                "Quantity: " + itemQuantity +
                "\nPrice per unit: " + ratePerUnitItem +
                "\nFinal rate: " + finalPrice;
            Console.WriteLine(output);

            Console.WriteLine("\n*********************************\n");
        }
    }
}

Настройка ставок GST, сопоставление товаров/категорий, прием пользовательских данных, расчет и т. д.

Длинный метод считается запахом кода.

После применения метода извлечения:

Чтобы избавиться от длинного метода, я разделил основной метод на небольшие методы, которые выполняют такие действия, как настройка ставок GST, сопоставление товаров/категорий, прием пользовательских данных, расчеты и так далее.

using System;
using System.Collections.Generic;

namespace NMart.Billing
{
    internal class NMartStore
    {
        private static Dictionary<string, int> CategoryGstRatesInPercentage = new Dictionary<string, int>();
        private static Dictionary<string, string> ItemsCategoryMapping = new Dictionary<string, string>();

        public static void Main()
        {
            SetupGstRateForCategories();

            SetupItemsPerCategory();

            Console.WriteLine("Welcome to NMart store");
            Console.WriteLine("***************************");

            string itemName;
            int itemQuantity, ratePerUnitItem;

            AcceptUserInput(out itemName, out itemQuantity, out ratePerUnitItem);

            double finalPrice = CalculateFinalRate(itemName, itemQuantity, ratePerUnitItem);

            PrintBillingDetails(itemName, itemQuantity, ratePerUnitItem, finalPrice);
        }

        private static void AcceptUserInput(out string itemName, out int itemQuantity, out int ratePerUnitItem)
        {
            Console.Write("Enter name of item: ");
            itemName = Console.ReadLine();
            Console.Write("Enter quantity of item: ");
            itemQuantity = int.Parse(Console.ReadLine());
            Console.Write("Enter rate per product item: ");
            ratePerUnitItem = int.Parse(Console.ReadLine());
        }

        private static double CalculateFinalRate(string itemName, int itemQuantity, int ratePerUnitItem)
        {
            string categoryName = GetCategory(itemName);

            int gstPercentageForItem = GetGstPercentage(categoryName);

            double gstRatePerItem = ratePerUnitItem * gstPercentageForItem / 100.0;

            double finalPrice = itemQuantity * (ratePerUnitItem + gstRatePerItem);

            return finalPrice;
        }

        private static string GetCategory(string itemName)
        {
            string categoryName = "";

            foreach (var item in ItemsCategoryMapping)
            {
                if (item.Key == itemName)
                {
                    categoryName = item.Value;
                    break;
                }
            }

            return categoryName;
        }

        private static int GetGstPercentage(string categoryName)
        {
            int gstPercentageForItem = 0;

            foreach (var categoryGstRate in CategoryGstRatesInPercentage)
            {
                if (categoryGstRate.Key == categoryName)
                {
                    gstPercentageForItem = categoryGstRate.Value;
                    break;
                }
            }

            return gstPercentageForItem;
        }

        private static void PrintBillingDetails(string itemName, int itemQuantity, int ratePerUnitItem, double finalPrice)
        {
            string output = "*******************************************\n" +
                "Billing Details for " + itemName + ":\n" +
                "*******************************************\n" +
                "Quantity: " + itemQuantity +
                "\nPrice per unit: " + ratePerUnitItem +
                "\nFinal rate: " + finalPrice;
            Console.WriteLine(output);

            Console.WriteLine("\n*********************************\n");
        }

        private static void SetupGstRateForCategories()
        {
            CategoryGstRatesInPercentage.Add("Food-grains", 0);
            CategoryGstRatesInPercentage.Add("Furniture", 5);
            CategoryGstRatesInPercentage.Add("Electronics", 18);
            CategoryGstRatesInPercentage.Add("Cosmetics", 28);
        }

        private static void SetupItemsForCosmetics()
        {
            ItemsCategoryMapping.Add("Shampoo", "Cosmetics");
            ItemsCategoryMapping.Add("Perfume", "Cosmetics");
        }

        private static void SetupItemsForElectronics()
        {
            ItemsCategoryMapping.Add("TV", "Electronics");
            ItemsCategoryMapping.Add("Mobile", "Electronics");
        }

        private static void SetupItemsForFoodGrains()
        {
            ItemsCategoryMapping.Add("Rice", "Food-grains");
            ItemsCategoryMapping.Add("Wheat", "Food-grains");
        }

        private static void SetupItemsForFurniture()
        {
            ItemsCategoryMapping.Add("Sofa", "Furniture");
            ItemsCategoryMapping.Add("Chairs", "Furniture");
        }

        private static void SetupItemsPerCategory()
        {
            SetupItemsForFoodGrains();
            SetupItemsForFurniture();
            SetupItemsForElectronics();
            SetupItemsForCosmetics();
        }
    }
}

Он делится на маленькие, сплоченные, мелкие методы, которые делают одну и только одну вещь. Они хорошо передают свои намерения.

Когда вы предпочитаете комментарий, чтобы выразить цель кода.

До

После

Блок кода, для которого был написан комментарий, я извлек этот блок кода в функцию: «ParseInput».

Когда метод извлечения помогает улучшить читаемость.

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

Когда происходит дублирование кода или копипаст.

Рассмотрим пример ниже, это дата форматирования, а код дублируется. Возможно, строки копируются и вставляются.

До

var formattedStartDate = startDate.ToString("dd MMMM yyyy"); 
var formattedEndDate = endDate.ToString("dd MMMM yyyy");

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

После

var formattedStartDate = FormatDate(startDate); 
var formattedEndDate = FormatDate(endDate); public string 
function FormatDate(DateTime date) { 
    return date.ToString("dd MMMM yyyy"); 
}

Преимущество

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

Наводит на размышления —

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

Первоначально опубликовано на https://beingcraftsman.com 31 июля 2018 г.