Статьи

Твердые принципы: принцип инверсии зависимостей

До сих пор мы рассматривали принципы единой ответственности , открытого / закрытого типа , замены ликов и разделения интерфейсов .
Инверсия зависимостей — один из последних принципов, на которые мы не обращаем внимания.
Принцип гласит, что

A. Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций.
Б. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Давайте начнем с некоторого кода, который нарушает этот принцип.
Как команда разработчиков программного обеспечения, мы должны реализовать проект. На данный момент команда разработчиков состоит из:

BackEnd Developer

1
2
3
4
5
6
7
package com.gkatzioura.solid.di;
 
public class BackEndDeveloper {
 
    public void writeJava() {
    }
}

И разработчик FrontEnd

1
2
3
4
5
6
7
8
package com.gkatzioura.solid.di;
 
public class FrontEndDeveloper {
 
    public void writeJavascript() {
    }
 
}

И наш проект использует как на протяжении всего процесса разработки.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package com.gkatzioura.solid.di;
 
public class Project {
 
    private BackEndDeveloper backEndDeveloper = new BackEndDeveloper();
    private FrontEndDeveloper frontEndDeveloper = new FrontEndDeveloper();
 
    public void implement() {
 
        backEndDeveloper.writeJava();
        frontEndDeveloper.writeJavascript();
    }
 
}

Итак, как мы видим, класс Project является модулем высокого уровня и зависит от модулей низкого уровня, таких как BackEndDeveloper и FrontEndDeveloper. На самом деле мы нарушаем первую часть принципа инверсии зависимостей.

Также, проверяя функцию реализации Project.class, мы понимаем, что методы writeJava и writeJavascript являются методами, привязанными к соответствующим классам. Относительно объема проекта это детали, так как в обоих случаях они являются формами развития. Таким образом, вторая часть принципа инверсии зависимости нарушается.

Для решения этой проблемы мы будем реализовывать интерфейс, называемый интерфейсом разработчика.

1
2
3
4
5
6
package com.gkatzioura.solid.di;
 
public interface Developer {
 
    void develop();
}

Поэтому мы вводим абстракцию.

BackEndDeveloper должен быть изменен на

01
02
03
04
05
06
07
08
09
10
11
12
13
package com.gkatzioura.solid.di;
 
public class BackEndDeveloper implements Developer {
 
    @Override
    public void develop() {
        writeJava();
    }
     
    private void writeJava() {
    }
     
}

И FrontEndDeveloper должен быть изменен на

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.gkatzioura.solid.di;
 
public class FrontEndDeveloper implements Developer {
 
    @Override
    public void develop() {
        writeJavascript();
    }
     
    public void writeJavascript() {
    }
     
}
[/sourecode]
 
The next step in order to tackle the violation of the first part would be to refactor the Project class so that it will not depend on the FrontEndDeveloper and the BackendDeveloper class.
 
 
package com.gkatzioura.solid.di;
 
import java.util.List;
 
public class Project {
 
    private List<Developer> developers;
     
    public Project(List<Developer> developers) {
     
        this.developers = developers;
    }
 
    public void implement() {
 
        developers.forEach(d->d.develop());
    }
 
}

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

Вы можете найти исходный код на github .

Также я составил шпаргалку, содержащую краткое изложение основных принципов. Зарегистрируйтесь в ссылке, чтобы получить его.

Опубликовано на Java Code Geeks с разрешения Эммануила Гкациоураса, партнера нашей программы JCG. Смотрите оригинальную статью здесь: Твердые принципы: принцип инверсии зависимости

Мнения, высказанные участниками Java Code Geeks, являются их собственными.