В книге "Чистый код" всё время говорится про то, что инверсия зависимостей - это замечательная вещь. Наверно, эта правда ввиду профессионализма и опыта автора, но я так и понял, как это можно "ссылаться только на абстракции, не указывая конкретных их реализаций".
Представлю свой ход мыслей, как я пытался это понять, начав с жестко связанного кода. В приведённом ниже Java-коде (окружение методом опущено) Realization
- одна из реализаций ISomeInterface
:
ISomeInterface example = new Realization();
Здесь переменная переменная имеет тип ISomeInterface
, но класс Realization
-то мы должны в явном виде импортировать в файл!
Далее, я знаю, что фреймворк Spring даёт нам контекст, из которого можно получить конкретные экземпляры классов (внедрение зависимостей). Уже лучше, чем пример выше, но имя бина-то мы в Java-коде указать всё равно должны! Получается, что тут ссылка на конкретную реализацию есть, но нет прямого импорта класса в файл.
Ну и плюс не понятно, что делать, когда нет фреймворка типа Spring (тем более что на данный момент мой основной язык - TypeScript). Так что в этом вопросе я прошу показать пример, как это так можно ссылаться на абстракции не импортируя в модуль её реализацию.
Все сводится к тому, что вы должны по максимуму использовать интерфейсы а не конкретную реализацию. Для любого вашего класса выполняющего какие-либо действия над сущностью вы пишите интерфейс, например:
public interface PersonService{
...
Person getPerson(Long id);
...
}
Все остальные классы ничего не знают о реализации данного метода. Они у себя внутри используют только метод getPersons(Long id)
. Соответственно они ничего не знают о реализации данного метода кроме того, что они должны передать ему на вход и что он возвращает. Вы не должны в других классах использовать специфические методы реализации, вы используете только те методы, которые есть в интерфейсе.
Таким образом у вас уменьшается связанность классов. Речь идет о том, что сам класс, например PersonControllerImpl
никак не должен изменится если вы поменяете внутреннюю реализацию метода в сервисе или сделаете другую реализацию интерфейса сервиса.
Например
public class PersonControllerImpl{
private PersonService service;
PersonControllerImpl(PersonService service){
this.service = service;
}
Person getPerson(Long id){
service.getPerson(id);
}
}
Ваш контроллер ничего не знает о реализации сервиса.
Конечно будет какой-то метод, который сделает new PersonServiceImpl()
и передаст его на вход в контроллер, но сам контроллер от реализации никак не зависит. Например:
class PersonsContainer{
private PersonService personService;
private PersonController personController;
PersonsContainer(){
personService = new PersonServiceImpl();
personController = new PersonControllerImpl( personService );
}
}
При таком подходе все что вам нужно для замены класса реализации сервиса, это поменять одну строчку в классе контейнера.
Spring при запуске тоже создает все инстансы конкретных сущностей, и когда вы внедряете зависимость по интерфейсу, он находит его имплементацию, если он ее не найдет он просто не запустится. Spring вынес обязанность создания объектов и ряд других задач в свои классы, которые в совокупности назвал контейнером.
Что это дает:
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
mbstring же устарел в 7х версиях пхптак почему же функции mb_ продолжают работать, без deprecated?
помогите, пожалуйста, исключить из кеширования следующий код (одна из функций в файле techmarket-woocommerce-template-functionsphp):
Есть wordpress фреймворк Unyson, работает на bootstrapПоддерживает расширения и кастомные опции