public string PrintInfo(IEnumerable<Month> months)
{
var salaryMoreWhen200 = false;
var monthsWhenSalaryMore200 = new List<Month>();
var totalSalary = SalaryByMonth.Sum(x =>
{
decimal value;
if (!months.Contains(x.Key))
return 0;
switch (x.Key)
{
case Month.April:
case Month.December:
value = x.Value;
break;
case Month.May:
value = x.Value + 12;
break;
default:
value = x.Value * 1.5m;
break;
}
if (value > 200)
{
salaryMoreWhen200 = true;
monthsWhenSalaryMore200.Add(x.Key);
}
return value;
});
var name = Name.ToUpper().Take(1).ToString() + Name.Skip(1);
if (salaryMoreWhen200)
return
$"name: {name} surname:{Surname} {totalSalary} monthMore200:{string.Join(string.Empty,monthsWhenSalaryMore200.Select(x => x.ToString()))}";
return $"name: {name} surname:{Surname} {totalSalary}";
}
Это метод класса, Person, имеющий доступ к имени, фамилии, и словарю(enum Month,decimal salary), назначение метода - вывести строку информации о человеке, вот так выглядит улучшенная версия с применением Extract Method
public decimal SalaryWithMonthСoefficient(decimal value, Month month)
{
switch (month)
{
case Month.April:
case Month.December:
return value;
case Month.May:
return value + 12;
default:
return value * 1.5m;
}
}
private decimal GetSalary(IEnumerable<Month> months)
{
var result = months
.Select(x => SalaryWithMonthСoefficient(SalaryByMonth[x], x))
.Sum();
return result;
}
private string FormatMonthsWhenSalaryMore200(IEnumerable<Month> months)
{
var monthsWhenSalaryMore200 =
months
.Select(x => SalaryWithMonthСoefficient(SalaryByMonth[x], x))
.Where(x => x > 200);
return string.Join(string.Empty, monthsWhenSalaryMore200.Select(x => x.ToString()));
}
private string FormatName() => Name.ToUpper().Take(1).ToString() + Name.Skip(1);
private string BuildInfoString(string nameTitle, string monthsWhenSalaryMore200, string salary)
{
if (monthsWhenSalaryMore200 != string.Empty)
return $"name: {nameTitle} surname:{Surname} salary:{salary} monthMore200 :{monthsWhenSalaryMore200}";
return $"name: {nameTitle} surname:{Surname} salary:{salary} ";
}
public string PrintInfo(IEnumerable<Month> months)
{
return BuildInfoString(FormatName(), FormatMonthsWhenSalaryMore200(months), $"{GetSalary(months)}");
}
C добавлением LINQ, количество строк кода возрасло в 2 раза, без него было бы в три, потому что пришлось бы итерироваться по коллекции
Обратите внимание на вынос switch в отдельный метод, это простой случай, когда(в данном случае) выражение не зависит от локальных переменных, таким же образом получился метод FormatName К сожалению, пример получился не совсем чистым, потому что я добавил LINQ и исключил использование bool переменной salaryMoreWhen200, но это нормально в процессе рефакторинга, также я исключил локальную переменную totalSalary, заменив на вызов метода GetSalary, это замена локальной переменной вызовом метода(Replace Temp with Query), что улучшило читаемость кода Таким образом удалось избавиться от всех локальных переменных,однако теперь я несколько раз итерируюсь по последовательности month, так что возможно в будущем придется оптимизировать это решение
Довольно простой способ уменьшить косвенность в коде, например:
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public Dictionary<Month, decimal> Months { get; set; }
public Person(string name, string surname, Dictionary<Month, decimal> months)
{
Name = name;
Surname = surname;
Months = months;
}
public decimal SalaryForFirstMonth() => Months.OrderBy(x => x.Key).First().Value;
public IOrderedEnumerable<KeyValuePair<Month, decimal>> OrderSalary() => Months.OrderBy(x => x.Key);
public void PrintSalary()
{
foreach (var salary in OrderedSalaryDictionary)
{
Console.WriteLine(salary.Value);
}
}
}
Можно заметить, что метод OrderSalary просто не нужен, заинлайним его в PrintSalary
public void PrintSalary()
{
foreach (var salary in Months.OrderBy(x => x.Key))
{
Console.WriteLine(salary.Value);
}
}
Выбран достаточно простой метод, также заинлайненый метод может принимать параметры, он становится основным претендентом на инлайнинг, когда используеться только в одном месте и его реализация достаточно четко дает понять, для чего он нужен
public decimal PrintSalary()
{
var salary1 = 0m;
foreach (var salary in Months.OrderBy(x => x.Key))
{
salary1 += salary.Value;
}
return salary1;
}
В данном случае переменная просто не нужна, она увеличивает время чтения кода, также, изобилие временных переменных приводит к сложности рефакторинга этого метода, например разбиение этого метода на части Правильный вариант:
public decimal PrintSalary()
{
return Months.OrderBy(x => x.Key).Sum(salary => salary.Value);
}