Недавно наша компания начала разработку нового веб-приложения на основе Java, и после некоторого процесса оценки мы решили использовать Spring.
Но многие члены команды не знают принципов Spring и Dependency Injection.
Поэтому меня попросили дать краткий курс о том, что такое Dependency Injection и основы Spring.
Вместо того, чтобы рассказывать всю теорию о IOC / DI, я подумал объяснить на примере.
Требование: Мы получим некоторый адрес клиента, и нам нужно подтвердить адрес. После некоторой оценки мы подумали об использовании службы проверки адресов Google.
Устаревший (плохой) подход:
Просто создайте класс AddressVerificationService и реализуйте логику.
Предположим, GoogleAddressVerificationService — это сервис, предоставляемый Google, который принимает адрес в качестве строки и возвращает долготу / широту.
class AddressVerificationService
{
//This method validates the given address and return longitude/latitude details.
public String validateAddress(String address)
{
GoogleAddressVerificationService gavs = new GoogleAddressVerificationService();
String result = gavs.validateAddress(address);
return result;
}
}
Проблемы с этим подходом:
1. Если вы хотите изменить своего поставщика услуг проверки адреса, вам нужно изменить логику.
2. Вы не можете выполнить модульное тестирование с помощью некоторого фиктивного AddressVerificationService (используя фиктивные объекты)
По какой-то причине Клиент просит нас поддержать нескольких провайдеров AddressVerificationService, и мы должны определить, какую службу использовать во время выполнения.
Для этого вы можете подумать об изменении вышеуказанного класса, как показано ниже:
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.
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 с несколькими сервисами провайдера.
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);
}
}
Теперь Клиент может выбрать, какой сервис Поставщика услуг использовать следующим образом:
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.
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.
Таким образом, следуя принципу внедрения зависимостей, мы можем создавать слабосвязанные и легко тестируемые сервисы на основе интерфейса.