Недавно наша компания начала разработку нового веб-приложения на основе 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.
Таким образом, следуя принципу внедрения зависимостей, мы можем создавать слабосвязанные и легко тестируемые сервисы на основе интерфейса.