Статьи

Как я объяснил инъекцию зависимости своей команде

Недавно наша компания начала разработку нового веб-приложения на основе Java, и после некоторого процесса оценки мы решили использовать Spring.
Но многие члены команды не знают принципов Spring и Dependency Injection. Поэтому меня попросили дать краткий курс о том, что такое Dependency Injection и основы Spring.

Вместо того, чтобы рассказывать всю теорию о IOC / DI, я подумал объяснить на примере.

Требование: Мы получим некоторый адрес клиента, и нам нужно подтвердить адрес.
После некоторой оценки мы подумали об использовании службы проверки адресов Google.

Устаревший (плохой) подход:

Просто создайте класс AddressVerificationService и реализуйте логику.

Предположим, GoogleAddressVerificationService — это сервис, предоставляемый Google, который принимает адрес в качестве строки и возвращает долготу / широту.

1
2
3
4
5
6
7
8
9
class AddressVerificationService
{
   public String validateAddress(String address)
 {
 GoogleAddressVerificationService gavs = new GoogleAddressVerificationService();
  String result = gavs.validateAddress(address); 
  return result;
 }
}

Проблемы с этим подходом:

1. Если вы хотите изменить своего поставщика услуг проверки адреса, вам нужно изменить логику.
2. Вы не можете выполнить модульное тестирование с помощью некоторого фиктивного AddressVerificationService (используя фиктивные объекты)

По какой-то причине Клиент просит нас поддержать нескольких провайдеров AddressVerificationService, и мы должны определить, какую службу использовать во время выполнения.

Для этого вы можете подумать об изменении вышеуказанного класса, как показано ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
class AddressVerificationService
{
//This method validates the given address and return longitude/latitude details.
 public String validateAddress(String address)
 {
  String result = null;
  int serviceCode = 2; // read this code value from a config file
  if(serviceCode == 1)
  {
   GoogleAddressVerificationService googleAVS = new GoogleAddressVerificationService();
   result = googleAVS.validateAddress(address);
  } else if(serviceCode == 2)
  {
   YahooAddressVerificationService yahooAVS = new YahooAddressVerificationService();
   result = yahooAVS.validateAddress(address);
  }
  return result;
 }
}

Проблемы с этим подходом:
 
1. Всякий раз, когда вам нужно поддержать нового поставщика услуг, вам нужно добавить / изменить логику, используя if-else-if.
2. Вы не можете выполнить модульное тестирование с помощью некоторого фиктивного AddressVerificationService (используя фиктивные объекты)

Подход IOC / DI:

В вышеупомянутых подходах AddressVerificationService берет на себя управление созданием своих зависимостей.
Таким образом, всякий раз, когда происходит изменение в его зависимостях, AddressVerificationService будет меняться.

Теперь давайте перепишем AddressVerificationService с использованием шаблона IOC / DI.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
class AddressVerificationService
{
 private AddressVerificationServiceProvider serviceProvider;
  
 public AddressVerificationService(AddressVerificationServiceProvider serviceProvider) {
  this.serviceProvider = serviceProvider;
 }
  
 public String validateAddress(String address)
 {
  return this.serviceProvider.validateAddress(address);
 }
}
 
interface AddressVerificationServiceProvider
{
 public String validateAddress(String address);
}

Здесь мы внедряем зависимость AddressVerificationService AddressVerificationServiceProvider.

Теперь давайте реализуем AddressVerificationServiceProvider с несколькими сервисами провайдера.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
class YahooAVS implements AddressVerificationServiceProvider
{
 @Override
 public String validateAddress(String address) {
  System.out.println("Verifying address using YAHOO AddressVerificationService");
  return yahooAVSAPI.validate(address);
 
}
 
class GoogleAVS implements AddressVerificationServiceProvider
{
 @Override
 public String validateAddress(String address) {
  System.out.println("Verifying address using Google AddressVerificationService");
  return googleAVSAPI.validate(address);
 }
}

Теперь Клиент может выбрать, какой сервис Поставщика услуг использовать следующим образом:

1
2
3
4
5
6
7
8
AddressVerificationService verificationService = null;
AddressVerificationServiceProvider provider = null;
provider = new YahooAVS();//to use YAHOO AVS
provider = new GoogleAVS();//to use Google AVS
 
verificationService = new AddressVerificationService(provider);
String lnl = verificationService.validateAddress("HitechCity, Hyderabad");
System.out.println(lnl);

Для модульного тестирования мы можем реализовать Mock AddressVerificationServiceProvider.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
class MockAVS implements AddressVerificationServiceProvider
{
 @Override
 public String validateAddress(String address) {
  System.out.println("Verifying address using MOCK AddressVerificationService");
  return "<response><longitude>123</longitude><latitude>4567</latitude>";
 }
}
 
AddressVerificationServiceProvider provider = null;
provider = new MockAVS();//to use MOCK AVS 
AddressVerificationServiceIOC verificationService = new AddressVerificationServiceIOC(provider);
String lnl = verificationService.validateAddress("Somajiguda, Hyderabad");
System.out.println(lnl);

С этим подходом мы перечислили проблемы с вышеупомянутыми подходами, не основанными на МОК / DI
1. Мы можем предоставить поддержку для любого количества провайдеров, сколько пожелаем. Просто внедрите AddressVerificationServiceProvider и вставьте его.
2. Мы можем выполнить модульное тестирование, используя фиктивные данные, используя Mock.

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

Ссылка: Как я объяснил инъекцию зависимостей в мою команду от нашего партнера по JCG Сивы Редди в блоге « Мои эксперименты по технологии» .