Тільки те, що система є складною, не означає, що ви повинні зробити її складною . Якщо у вас клас із занадто великою кількістю залежностей (або Співробітників) на кшталт цього:
public class MyAwesomeClass {
public class MyAwesomeClass(IDependency1 _d1, IDependency2 _d2, ... , IDependency20 _d20) {
// Assign it all
}
}
... тоді це стало занадто складним, і ви насправді не стежите за SRP , чи не так? Я ставлюся під заклад, якщо ви записували те, що MyAwesomeClassробиться на картці CRC, це не вміщується на індексній картці, або ви повинні писати справді крихітні нерозбірливі літери.
Тут у вас є те, що ваші хлопці лише дотримувались принципу розбиття інтерфейсів, і, можливо, це довели до крайності, але це вже зовсім інша історія. Ви можете стверджувати, що залежності - це доменні об'єкти (що трапляється), однак наявність класу, який одночасно обробляє 20 об’єктів домену, розтягує його трохи надто далеко.
TDD дасть вам хороший показник того, наскільки клас працює. Тупо кажучи; якщо метод тестування має код налаштування, який потрібно писати назавжди (навіть якщо ви перефактуруєте тести), MyAwesomeClassможливо, у вас є занадто багато чого робити.
То як ти вирішиш цю загадку? Ви переносите свої обов'язки на інші класи. Ви можете зробити кілька кроків для класу, який має цю проблему:
- Визначте всі дії (чи обов'язки), які робить ваш клас із залежностями.
- Групуйте дії відповідно до тісно пов'язаних залежностей.
- Повторний випуск! Тобто рефактор кожного з виявлених дій або до нових, або (що ще важливіше) інших класів.
Абстрактний приклад відповідальності рефакторингу
Нехай Cбуде клас , який має кілька залежностей D1, D2, D3, D4що вам потрібно реорганізувати , щоб використовувати менше. Коли ми визначаємо, якими методами Cвикликає залежність, ми можемо скласти простий її список:
D1- performA(D2),performB()
D2 - performD(D1)
D3 - performE()
D4 - performF(D3)
Дивлячись на список, ми можемо побачити це D1і D2пов'язані між собою, оскільки клас хоч якось потребує їх разом. Ми також можемо побачити, що D4потрібно D3. Отже, у нас є дві групи:
Group 1- D1<->D2
Group 2- D4->D3
Групування - це показник того, що зараз клас має два обов'язки.
Group 1- Один для обробки виклику двох об'єктів, які потребують один одного. Можливо, ви можете дозволити своєму класу Cусунути необхідність поводження з обома залежностями та залишити один із них обробляти ці виклики. У цій групуванні очевидно, що це D1може мати посилання на D2.
Group 2- Інша відповідальність потребує одного об'єкта для виклику іншого. Ви не можете D4впоратися D3замість вашого класу? Тоді ми, мабуть, можемо виключити D3з класу C, дозволивши D4робити дзвінки замість цього.
Не сприймайте мою відповідь як встановлену в камені, тому що приклад дуже абстрактний і робить багато припущень. Я впевнений, що існує більше способів відновити це, але, принаймні, ці кроки можуть допомогти вам отримати якийсь процес переміщення обов'язків, а не розділяти класи.
Редагувати:
Серед коментарів @Emmad Karem говорить:
"Якщо ваш клас має 20 параметрів у конструкторі, це не здається, що ваша команда зовсім знає, що таке SRP. Якщо у вас клас, який робить лише одне, то як він має 20 залежностей?" - Я думаю, що якщо ви мати клас клієнта, не дивно мати 20 параметрів у конструкторі.
Це правда, що для об'єктів DAO, як правило, є багато параметрів, які ви повинні встановити у своєму конструкторі, а параметри, як правило, є простими типами, такими як рядок. Однак у прикладі Customerкласу ви все ще можете згрупувати його властивості всередині інших класів, щоб зробити речі простішими. Такі , як має Addressклас з вулиць і Zipcodeклас , який містить поштовий індекс і буде обробляти бізнес - логіку , такі як перевірка достовірності даних , а також:
public class Address {
private String street1;
//...
private Zipcode zipcode;
// easy to extend
public bool isValid() {
return zipcode.isValid();
}
}
public class Zipcode {
private string zipcode;
public bool isValid() {
// return regex match that zipcode contains numbers
}
}
Ця річ обговорюється далі у публікації блогу "Ніколи, ніколи, ніколи не використовуй String на Java (або принаймні часто)" . В якості альтернативи використання конструкторів або статичних методів для полегшення створення під об’єктів ви можете використовувати шаблон побудови рідини .