SlideShare a Scribd company logo
1 of 20
Методы рефакторинга кода
программного обеспечения
• Встраивание класса (Inline Class)
• Введение локального расширения
(Introduce Local Extension)
• Замена вложенных условных операторов
граничным оператором
(Replace Nested Conditional with Guard Clauses)
Встраивание класса
Также известен как: Inline Class
Проблема Решение
Класс почти ничего не делает, ни за что не
отвечает, и никакой ответственности для
этого класса не планируется.
Переместите все члены и
полезные функции из описанного
класса в другой.
Встраивание класса
Также известен как: Inline Class
«Встраивание класса» (InlineClass) противоположно
«Выделению класса» (ExtractClass). Прибегать к этой
операции нужно, если от класса становится мало
пользы и его надо убрать. Часто это происходит в
результате рефакторинга, оставившего в классе
мало функций. В этом случае следует вставить
данный класс в другой, выбрав для этого такой
класс, который чаще всего его использует.
Причины рефакторинга Достоинства
Меньше бесполезных классов — больше
свободной оперативной памяти, в том числе, и у
вас в голове.
Встраивание класса
Пример кода
public class ClinicInfo
{
public ClinicInfo()
{
Doctors = new HashSet<Doctor>();
}
[Required]
public string Name { get; set; }
[Required]
public string Adress { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string BankCard { get; set; }
public byte[] Image { get; set; }
public virtual ICollection<Doctor> Doctors { get; set; }
public Doctor GetDoctors(Specialization specification)
=> DoctorInforms.Where(x => x.Specialization ==
specification);
}
public class Clinic
{
[Key]
public int Id { get; set; }
public bool ClinicConfirmed { get; set; }
public virtual ClinicInfo ClinicInfo { get; set; }
}
Встраивание класса
Порядок рефакторинга
1) Создайте в классе-приёмнике публичные
поля и методы, которые есть в классе-доноре.
Методы должны обращаться к аналогичным
методам класса-донора.
public class Clinic
{
[Key]
public int Id { get; set; }
public bool ClinicConfirmed { get; set; }
public virtual ClinicInfo ClinicInfo { get; set; }
}
public string Name => ClinicInfo.Name;
public string Adress => ClinicInfo.Adress;
public string Description => ClinicInfo.Description;
public string BankCard => ClinicInfo.BankCard;
public byte[] Image => ClinicInfo.Image;
public virtual ICollection<Doctor> Doctors
=> ClinicInfo.Doctors
public Doctor GetDoctors(Specialization specification)
=> ClinicInfo.GetDoctors(specialization);
Встраивание класса
Порядок рефакторинга
2) Замените все обращения к классу-донору
обращениями к полям и методам класса-
приёмника.
public List<Doctor> GetClinicDoctors(int clinicId,
string specializations)
{
var clinic = db.Clinics.Find(clinicId);
return clinic.ClinicInfo.GetDoctors(specialization);
}
public List<Doctor> GetClinicDoctors(int clinicId,
string specializations)
{
var clinic = db.Clinics.Find(clinicId);
return clinic.GetDoctors(specialization);
}
Встраивание класса
Порядок рефакторинга
3) Самое время протестировать программу и
убедиться, что во время работы не было
допущено никаких ошибок. Если тесты
показали, что все работает так, как должно,
начинаем использовать перемещение
метода и перемещение поля для того, чтобы
полностью переместить все функциональности
в класс-приёмник из исходного класса.
Продолжаем делать это, пока исходный класс
не окажется совсем пустым.
public class Clinic
{
[Key]
public int Id { get; set; }
public bool ClinicConfirmed { get; set; }
public virtual ClinicInfo ClinicInfo { get; set; }
}
public string Name { get; set; }
public string Adress { get; set; }
public string Description { get; set; }
public string BankCard { get; set; }
public byte[] Image { get; set; }
public virtual ICollection<Doctor> Doctors{ get; set; }
public Doctor GetDoctors(Specialization specification)
=> DoctorInforms
.Where(x => x.Specialization == specification);
Встраивание класса
Порядок рефакторинга
4) Удалите исходный класс.
public class Clinic
{
[Key]
public int Id { get; set; }
public bool ClinicConfirmed { get; set; }
X public virtual ClinicInfo ClinicInfo { get; set; }
}
public string Name { get; set; }
public string Adress { get; set; }
public string Description { get; set; }
public string BankCard { get; set; }
public byte[] Image { get; set; }
public virtual ICollection<Doctor> Doctors{ get; set; }
public Doctor GetDoctors(Specialization specification)
=> DoctorInforms
.Where(x => x.Specialization == specification);
Введение локального расширения
Также известен как: Introduce Local Extension
Проблема Решение
В служебном классе отсутствуют некоторые
методы, которые вам нужны. При этом
добавить их в этот класс вы не можете.
Создайте новый класс, который
бы содержал эти методы, и
сделайте его наследником
служебного класса, либо его
обёрткой.
В классе, который вы используете, нет нужных вам
методов. Или ещё хуже — вы не можете их туда
добавить (например, потому что классы находятся
в сторонней библиотеке).
Причины рефакторинга Пути решения
Есть три пути:
• Создать подкласс из интересующего класса,
который будет содержать новые методы, и
наследовать все остальное из родительского
класса. Этот путь проще, но иногда бывает
заблокирован в самом служебном классе с
помощью директивы final (Java) / sealed (C#)
• Создать класс-обёртку, который будет
содержать все новые методы, а остальное
делегировать связанному объекту служебного
класса.
• Создать статические методы расширения (С#).
Введение локального расширения
Также известен как: Introduce Local Extension
Помещая дополнительные методы в отдельный
класс-расширение (обёртку или подкласс), вы не
засоряете клиентские классы кодом, который им не
принадлежит по смыслу. Этим повышается
связность компонентов программы и возможность
их повторного использования.
Достоинства
Пример кода
Введение локального расширения
public List<Payment> GePayments(Clinic clinic, DateTime day)
{
var allPayments = clinic.Doctors.SelectMany(doctor => doctor.Appointmnets)
.Where(appointment => appointment.Date == day)
.SelectMany(doctor => doctor.Payments);
var resultPayment = new List<Payment>();
foreach(var payment in allPayments)
{
if (!resultPayment.Any(x => x.AppoinmentId == payment.AppoinmentId))
resultPayment.Add(payment);
}
return allPayments;
}
Порядок рефакторинга
1) Создайте новый класс-расширение:
для C# - необходимо создать статический
класс, в котором будут находиться методы
расширения.
public static class IEnumerableExtension
{
}
Введение локального расширения
Порядок рефакторинга
public static class IEnumerableExtension
{
}
2) Создайте в классе новые
расширенные методы. Переместите в
него внешние методы из других классов,
либо удалите их, если расширение уже
имеет такой функционал.
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T>
source, Func<T, TKey> keySelector)
{
if (source == null)
yield return default(TSource);
HashSet<TKey> seenKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (seenKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
Введение локального расширения
Порядок рефакторинга
3) Замените использование служебного класса новым классом-расширением в тех местах, где
нужна расширенная функциональность.
public List<Payment> GePayments(Clinic clinic, DateTime day)
{
var allPayments = clinic.Doctors
.SelectMany(doctor => doctor.Appointmnets)
.Where(appointment => appointment.Date == day)
.SelectMany(doctor => doctor.Payments);
return allPayments.DistinctBy(x => x.AppoinmentId);
}
Введение локального расширения
Замена вложенных условных операторов граничным
оператором
Также известен как: Replace Nested Conditional with Guard Clauses
Проблема Решение
У вас есть группа вложенных условных операторов,
среди которых сложно выделить нормальный ход
выполнения кода.
Выделите все проверки специальных или граничных
случаев выполнения в отдельные условия и
поместите их перед основными проверками. В
идеале, вы должны получить «плоский» список
условных операторов, идущих один за другим.
Разобраться в том, что и как делает оператор с
большим уровнем вложенности довольно сложно,
так как «нормальный» ход выполнения в нем не
очевиден. Такие операторы появляются
эволюционным путём, когда каждое из условий
добавляется в разные промежутки времени без
мыслей об оптимизации остальных условий.
Чтобы упростить такой оператор, нужно
выделить все особые случаи в отдельные условные
операторы, которые бы при наступлении
граничных условий, сразу заканчивали выполнение
и возвращали нужное значение. По сути, ваша
цель — сделать такой оператор плоским.
Причины рефакторинга
Замена вложенных условных операторов граничным
оператором
Также известен как: Replace Nested Conditional with Guard Clauses
Пример кода
Замена вложенных условных операторов граничным
оператором
public Doctor EditClinicDoctor(Clinic clinic, int[] doctorIds)
{
if(clinic != null)
{
clinic.Doctors.Clear();
foreach(int doctorId in doctorIds)
{
var doctor = db.Doctors.Find(doctorId);
if(doctor != null)
{
clinic.Doctors.Add(doctor);
}
else
{
throw new Exception($"There are no doctor with id {doctorId}");
}
}
}
else
{
throw new Exception("clinic cann't be null!");
}
}
1
2
3
Порядок рефакторинга
Замена вложенных условных операторов граничным
оператором
Постарайтесь избавиться от «побочных
эффектов» в условиях операторов. Разделение
запроса и модификатора может в этом помочь. Такое
решение понадобится для дальнейших перестановок
условий.
1.Выделите граничные условия, которые приводят к
вызову исключения или немедленному возвращению
значения из метода. Переместите эти условия в
начало метода.
2.После того как с переносами покончено, и все тесты
стали проходить, проверьте, можно ли
использовать объединение условных
операторов для граничных условных операторов,
ведущих к одинаковым исключениям или
возвращаемым значениям.
public Clinic EditClinicDoctor(Clinic clinic,
int[] doctorIds)
{
if(clinic == null)
throw new Exception("clinic cann't be null!");
clinic.Doctors.Clear();
foreach(int doctorId in doctorIds)
{
var doctor = db.Doctors.Find(doctorId);
if(doctor == null)
throw new Exception(“Exception message…”);
clinic.Doctors.Add(doctor);
}
return clinic;
}
Источники
М.Фаулер - Рефакторинг. Улучшение проекта существующего кода
• Встраивание класса – 104 с.
• Введение локального расширения - 109 с.
• Замена вложенных условных операторов граничным оператором – 164 с.
Спасибо за внимание

More Related Content

Similar to АРК-ПЗ-1.pptx

Шаблоны проектирования в Magento
Шаблоны проектирования в MagentoШаблоны проектирования в Magento
Шаблоны проектирования в MagentoPavel Usachev
 
Dependency injection
Dependency injectionDependency injection
Dependency injectionGetDev.NET
 
Java Core. Lecture# 2. Classes & objects.
Java Core. Lecture# 2. Classes & objects.Java Core. Lecture# 2. Classes & objects.
Java Core. Lecture# 2. Classes & objects.Anton Moiseenko
 
C# Desktop. Занятие 16.
C# Desktop. Занятие 16.C# Desktop. Занятие 16.
C# Desktop. Занятие 16.Igor Shkulipa
 
Dependency injection на примере unity и n inject
Dependency injection на примере unity и n injectDependency injection на примере unity и n inject
Dependency injection на примере unity и n injectRoman Kalita
 
Dependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInjectDependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInjectakrakovetsky
 
C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.Igor Shkulipa
 
PostSharp - Threading Model Library
PostSharp - Threading Model LibraryPostSharp - Threading Model Library
PostSharp - Threading Model LibraryAndrey Gordienkov
 
Java 9: what is there beyond modularization
Java 9: what is there beyond modularizationJava 9: what is there beyond modularization
Java 9: what is there beyond modularizationIvan Krylov
 
Референсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVCРеференсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVCAndrew Mayorov
 
Aleksey Mashanov Rit
Aleksey Mashanov RitAleksey Mashanov Rit
Aleksey Mashanov Ritrit2010
 
Aleksey Mashanov Rit
Aleksey  Mashanov RitAleksey  Mashanov Rit
Aleksey Mashanov Ritrit2010
 
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...Ontico
 
C++ осень 2013 лекция 4
C++ осень 2013 лекция 4C++ осень 2013 лекция 4
C++ осень 2013 лекция 4Technopark
 
Java осень 2012 лекция 9
Java осень 2012 лекция 9Java осень 2012 лекция 9
Java осень 2012 лекция 9Technopark
 
Общие темы. Тема 02.
Общие темы. Тема 02.Общие темы. Тема 02.
Общие темы. Тема 02.Igor Shkulipa
 

Similar to АРК-ПЗ-1.pptx (20)

Шаблоны проектирования в Magento
Шаблоны проектирования в MagentoШаблоны проектирования в Magento
Шаблоны проектирования в Magento
 
Dependency injection
Dependency injectionDependency injection
Dependency injection
 
Unit тесты java
Unit тесты javaUnit тесты java
Unit тесты java
 
Java Core. Lecture# 2. Classes & objects.
Java Core. Lecture# 2. Classes & objects.Java Core. Lecture# 2. Classes & objects.
Java Core. Lecture# 2. Classes & objects.
 
C# Desktop. Занятие 16.
C# Desktop. Занятие 16.C# Desktop. Занятие 16.
C# Desktop. Занятие 16.
 
Dependency injection на примере unity и n inject
Dependency injection на примере unity и n injectDependency injection на примере unity и n inject
Dependency injection на примере unity и n inject
 
Dependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInjectDependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInject
 
C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.
 
PostSharp - Threading Model
PostSharp - Threading ModelPostSharp - Threading Model
PostSharp - Threading Model
 
PostSharp - Threading Model Library
PostSharp - Threading Model LibraryPostSharp - Threading Model Library
PostSharp - Threading Model Library
 
Java 9: what is there beyond modularization
Java 9: what is there beyond modularizationJava 9: what is there beyond modularization
Java 9: what is there beyond modularization
 
Референсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVCРеференсная архитектура приложения на ASP.NET MVC
Референсная архитектура приложения на ASP.NET MVC
 
Aleksey Mashanov Rit
Aleksey Mashanov RitAleksey Mashanov Rit
Aleksey Mashanov Rit
 
Aleksey Mashanov Rit
Aleksey  Mashanov RitAleksey  Mashanov Rit
Aleksey Mashanov Rit
 
Jira as a test management tool
Jira as a test management toolJira as a test management tool
Jira as a test management tool
 
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
TDD: когда нужно и, самое главное, когда не нужно / Павел Калашников (SimbirS...
 
C++ осень 2013 лекция 4
C++ осень 2013 лекция 4C++ осень 2013 лекция 4
C++ осень 2013 лекция 4
 
Java осень 2012 лекция 9
Java осень 2012 лекция 9Java осень 2012 лекция 9
Java осень 2012 лекция 9
 
Общие темы. Тема 02.
Общие темы. Тема 02.Общие темы. Тема 02.
Общие темы. Тема 02.
 
Jira as a test management tool
Jira as a test management toolJira as a test management tool
Jira as a test management tool
 

АРК-ПЗ-1.pptx

  • 1. Методы рефакторинга кода программного обеспечения • Встраивание класса (Inline Class) • Введение локального расширения (Introduce Local Extension) • Замена вложенных условных операторов граничным оператором (Replace Nested Conditional with Guard Clauses)
  • 2. Встраивание класса Также известен как: Inline Class Проблема Решение Класс почти ничего не делает, ни за что не отвечает, и никакой ответственности для этого класса не планируется. Переместите все члены и полезные функции из описанного класса в другой.
  • 3. Встраивание класса Также известен как: Inline Class «Встраивание класса» (InlineClass) противоположно «Выделению класса» (ExtractClass). Прибегать к этой операции нужно, если от класса становится мало пользы и его надо убрать. Часто это происходит в результате рефакторинга, оставившего в классе мало функций. В этом случае следует вставить данный класс в другой, выбрав для этого такой класс, который чаще всего его использует. Причины рефакторинга Достоинства Меньше бесполезных классов — больше свободной оперативной памяти, в том числе, и у вас в голове.
  • 4. Встраивание класса Пример кода public class ClinicInfo { public ClinicInfo() { Doctors = new HashSet<Doctor>(); } [Required] public string Name { get; set; } [Required] public string Adress { get; set; } [Required] public string Description { get; set; } [Required] public string BankCard { get; set; } public byte[] Image { get; set; } public virtual ICollection<Doctor> Doctors { get; set; } public Doctor GetDoctors(Specialization specification) => DoctorInforms.Where(x => x.Specialization == specification); } public class Clinic { [Key] public int Id { get; set; } public bool ClinicConfirmed { get; set; } public virtual ClinicInfo ClinicInfo { get; set; } }
  • 5. Встраивание класса Порядок рефакторинга 1) Создайте в классе-приёмнике публичные поля и методы, которые есть в классе-доноре. Методы должны обращаться к аналогичным методам класса-донора. public class Clinic { [Key] public int Id { get; set; } public bool ClinicConfirmed { get; set; } public virtual ClinicInfo ClinicInfo { get; set; } } public string Name => ClinicInfo.Name; public string Adress => ClinicInfo.Adress; public string Description => ClinicInfo.Description; public string BankCard => ClinicInfo.BankCard; public byte[] Image => ClinicInfo.Image; public virtual ICollection<Doctor> Doctors => ClinicInfo.Doctors public Doctor GetDoctors(Specialization specification) => ClinicInfo.GetDoctors(specialization);
  • 6. Встраивание класса Порядок рефакторинга 2) Замените все обращения к классу-донору обращениями к полям и методам класса- приёмника. public List<Doctor> GetClinicDoctors(int clinicId, string specializations) { var clinic = db.Clinics.Find(clinicId); return clinic.ClinicInfo.GetDoctors(specialization); } public List<Doctor> GetClinicDoctors(int clinicId, string specializations) { var clinic = db.Clinics.Find(clinicId); return clinic.GetDoctors(specialization); }
  • 7. Встраивание класса Порядок рефакторинга 3) Самое время протестировать программу и убедиться, что во время работы не было допущено никаких ошибок. Если тесты показали, что все работает так, как должно, начинаем использовать перемещение метода и перемещение поля для того, чтобы полностью переместить все функциональности в класс-приёмник из исходного класса. Продолжаем делать это, пока исходный класс не окажется совсем пустым. public class Clinic { [Key] public int Id { get; set; } public bool ClinicConfirmed { get; set; } public virtual ClinicInfo ClinicInfo { get; set; } } public string Name { get; set; } public string Adress { get; set; } public string Description { get; set; } public string BankCard { get; set; } public byte[] Image { get; set; } public virtual ICollection<Doctor> Doctors{ get; set; } public Doctor GetDoctors(Specialization specification) => DoctorInforms .Where(x => x.Specialization == specification);
  • 8. Встраивание класса Порядок рефакторинга 4) Удалите исходный класс. public class Clinic { [Key] public int Id { get; set; } public bool ClinicConfirmed { get; set; } X public virtual ClinicInfo ClinicInfo { get; set; } } public string Name { get; set; } public string Adress { get; set; } public string Description { get; set; } public string BankCard { get; set; } public byte[] Image { get; set; } public virtual ICollection<Doctor> Doctors{ get; set; } public Doctor GetDoctors(Specialization specification) => DoctorInforms .Where(x => x.Specialization == specification);
  • 9. Введение локального расширения Также известен как: Introduce Local Extension Проблема Решение В служебном классе отсутствуют некоторые методы, которые вам нужны. При этом добавить их в этот класс вы не можете. Создайте новый класс, который бы содержал эти методы, и сделайте его наследником служебного класса, либо его обёрткой.
  • 10. В классе, который вы используете, нет нужных вам методов. Или ещё хуже — вы не можете их туда добавить (например, потому что классы находятся в сторонней библиотеке). Причины рефакторинга Пути решения Есть три пути: • Создать подкласс из интересующего класса, который будет содержать новые методы, и наследовать все остальное из родительского класса. Этот путь проще, но иногда бывает заблокирован в самом служебном классе с помощью директивы final (Java) / sealed (C#) • Создать класс-обёртку, который будет содержать все новые методы, а остальное делегировать связанному объекту служебного класса. • Создать статические методы расширения (С#). Введение локального расширения Также известен как: Introduce Local Extension Помещая дополнительные методы в отдельный класс-расширение (обёртку или подкласс), вы не засоряете клиентские классы кодом, который им не принадлежит по смыслу. Этим повышается связность компонентов программы и возможность их повторного использования. Достоинства
  • 11. Пример кода Введение локального расширения public List<Payment> GePayments(Clinic clinic, DateTime day) { var allPayments = clinic.Doctors.SelectMany(doctor => doctor.Appointmnets) .Where(appointment => appointment.Date == day) .SelectMany(doctor => doctor.Payments); var resultPayment = new List<Payment>(); foreach(var payment in allPayments) { if (!resultPayment.Any(x => x.AppoinmentId == payment.AppoinmentId)) resultPayment.Add(payment); } return allPayments; }
  • 12. Порядок рефакторинга 1) Создайте новый класс-расширение: для C# - необходимо создать статический класс, в котором будут находиться методы расширения. public static class IEnumerableExtension { } Введение локального расширения
  • 13. Порядок рефакторинга public static class IEnumerableExtension { } 2) Создайте в классе новые расширенные методы. Переместите в него внешние методы из других классов, либо удалите их, если расширение уже имеет такой функционал. public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector) { if (source == null) yield return default(TSource); HashSet<TKey> seenKeys = new HashSet<TKey>(); foreach (TSource element in source) { if (seenKeys.Add(keySelector(element))) { yield return element; } } } Введение локального расширения
  • 14. Порядок рефакторинга 3) Замените использование служебного класса новым классом-расширением в тех местах, где нужна расширенная функциональность. public List<Payment> GePayments(Clinic clinic, DateTime day) { var allPayments = clinic.Doctors .SelectMany(doctor => doctor.Appointmnets) .Where(appointment => appointment.Date == day) .SelectMany(doctor => doctor.Payments); return allPayments.DistinctBy(x => x.AppoinmentId); } Введение локального расширения
  • 15. Замена вложенных условных операторов граничным оператором Также известен как: Replace Nested Conditional with Guard Clauses Проблема Решение У вас есть группа вложенных условных операторов, среди которых сложно выделить нормальный ход выполнения кода. Выделите все проверки специальных или граничных случаев выполнения в отдельные условия и поместите их перед основными проверками. В идеале, вы должны получить «плоский» список условных операторов, идущих один за другим.
  • 16. Разобраться в том, что и как делает оператор с большим уровнем вложенности довольно сложно, так как «нормальный» ход выполнения в нем не очевиден. Такие операторы появляются эволюционным путём, когда каждое из условий добавляется в разные промежутки времени без мыслей об оптимизации остальных условий. Чтобы упростить такой оператор, нужно выделить все особые случаи в отдельные условные операторы, которые бы при наступлении граничных условий, сразу заканчивали выполнение и возвращали нужное значение. По сути, ваша цель — сделать такой оператор плоским. Причины рефакторинга Замена вложенных условных операторов граничным оператором Также известен как: Replace Nested Conditional with Guard Clauses
  • 17. Пример кода Замена вложенных условных операторов граничным оператором public Doctor EditClinicDoctor(Clinic clinic, int[] doctorIds) { if(clinic != null) { clinic.Doctors.Clear(); foreach(int doctorId in doctorIds) { var doctor = db.Doctors.Find(doctorId); if(doctor != null) { clinic.Doctors.Add(doctor); } else { throw new Exception($"There are no doctor with id {doctorId}"); } } } else { throw new Exception("clinic cann't be null!"); } } 1 2 3
  • 18. Порядок рефакторинга Замена вложенных условных операторов граничным оператором Постарайтесь избавиться от «побочных эффектов» в условиях операторов. Разделение запроса и модификатора может в этом помочь. Такое решение понадобится для дальнейших перестановок условий. 1.Выделите граничные условия, которые приводят к вызову исключения или немедленному возвращению значения из метода. Переместите эти условия в начало метода. 2.После того как с переносами покончено, и все тесты стали проходить, проверьте, можно ли использовать объединение условных операторов для граничных условных операторов, ведущих к одинаковым исключениям или возвращаемым значениям. public Clinic EditClinicDoctor(Clinic clinic, int[] doctorIds) { if(clinic == null) throw new Exception("clinic cann't be null!"); clinic.Doctors.Clear(); foreach(int doctorId in doctorIds) { var doctor = db.Doctors.Find(doctorId); if(doctor == null) throw new Exception(“Exception message…”); clinic.Doctors.Add(doctor); } return clinic; }
  • 19. Источники М.Фаулер - Рефакторинг. Улучшение проекта существующего кода • Встраивание класса – 104 с. • Введение локального расширения - 109 с. • Замена вложенных условных операторов граничным оператором – 164 с.