Статьи

Внедрение зависимостей Spring — Field vs Setter vs Constructor Injection

Добро пожаловать в учебник Spring Inpendency Injection — Field vs Setter vs Constructor Injection . Узнайте разницу между полевым впрыском , сеттерным впрыском и конструктором . С помощью примеров кода мы увидим преимущества использования каждого из них и почему стоит выбирать один из них над другим.

Подробнее о инъекции зависимостей весной:

обзор

В Spring Framework внедрение зависимостей бывает трех типов. Это полевая инъекция , сеттерная инъекция и конструктор . Вы можете абсолютно использовать любой из них, и они приводят к абсолютно одинаковому результату. Однако, основываясь на простоте, удобочитаемости, стандартах кодирования или лучших методах кодирования, между ними мало различий. Прежде чем мы посмотрим, каковы эти различия, очень быстро, мы увидим все три типа инъекций зависимостей в действии.

Внедрение зависимостей на основе полей

01
02
03
04
05
06
07
08
09
10
11
12
13
@Component
public class MyClass {
 
    @Autowired private DogsController controller;
    @Autowired private DogsService service;
    @Autowired private DogsDao dao;
    @Autowired private ApplicationProperties properties;
 
 
    //...
    // Business methods
    //
}

Внедрение зависимостей на основе сеттера

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
@Component
public class MyClass {
 
    private DogsController controller;
    private DogsService service;
    private DogsDao dao;
    private ApplicationProperties properties;
 
    @Autowired
    public void setController(DogsController controller) {
        this.controller = controller;
    }
 
    @Autowired
    public void setService(DogsService service) {
        this.service = service;
    }
 
    @Autowired
    public void setDao(DogsDao dao) {
        this.dao = dao;
    }
 
    @Autowired
    public void setProperties(ApplicationProperties properties) {
        this.properties = properties;
    }
 
 
    //...
    // Business methods
    //
}

Внедрение зависимостей на основе конструктора

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@Component
public class MyClass {
 
    private DogsController controller;
    private DogsService service;
    private DogsDao dao;
    private ApplicationProperties properties;
 
    @Autowired
    public MyClass(DogsController controller, DogsService service, DogsDao dao, ApplicationProperties properties) {
        this.controller = controller;
        this.service = service;
        this.dao = dao;
        this.properties = properties;
    }
 
    //...
    // Business methods
    //
}

У нас есть ссылки на код для всех трех типов инъекций зависимостей. Давайте оценим их по некоторым важным аспектам принципов объектно-ориентированного проектирования.

читабельность

Удобочитаемость — это суждение людей о том, насколько легко понять программу или ее часть. Разработчик тратит 30% времени на написание программного обеспечения и 70% времени на его обслуживание. Читаемость повышает удобство сопровождения программного обеспечения. Когда разработчик смотрит на класс, он / она должен быстро сосредоточиться на жизненно важных частях класса, не отвлекаясь на код платформы или другие компоненты платформы.

Давайте применим меру читабельности ко всем трем

  • Field Injection : The Best. Меньше шаблонного кода. Основное внимание уделяется бизнес-логике.
  • Конструктор Инъекция : лучше. Конструкторы визуально стоят отдельно от методов.
  • Сеттер впрыска: худший Добавлены 4 метода экземпляра. Отнимает фокус от бизнес-методов.

неизменность

С точки зрения программирования, объект называется неизменным, если его состояние не может быть изменено после создания. Неизменность является действительно важным принципом хорошего объектно-ориентированного программирования. Неизменяемость обеспечивает безопасность потоков, состояние и читаемость классов.

Если мы посмотрим на приведенные выше примеры, в перспективе неизменности .

  • Инъектор конструктора : Поддерживает неизменность.
  • Инъекция сеттера : нет неизменности.
  • Инъекция поля : нет неизменности.

Государственная безопасность

Скорее всего, объект создается пользователями или базовой структурой. Сам объект должен предоставлять правила или рекомендации для экземпляров, чтобы они вызывали объект в правильном состоянии. Если Объект не предписывает такую ​​безопасность состояния, существует возможность создания экземпляров объектов в неполных или неправильных состояниях.

Примечание . Все приведенные выше примеры защищены от состояний, поскольку Spring разрешает их зависимости, и Spring правильно инициализирует все поля, которые являются частью @Autowired . Но некоторые потребители могут создать экземпляр вашего объекта с new ключевым словом. Мы должны смотреть на безопасность государства за пределами Spring Framework.

Давайте применим меры государственной безопасности ко всем примерам, которые мы видели.

  • Конструктор инъекций : государственный сейф. Объект создается до полного состояния или не создается вообще.
  • Внедрение сеттера : потребитель использует конструктор без аргументов. И возможность пропустить вызов одного из установщиков или дважды вызвать один и тот же установщик с другим значением (ошибки копирования-вставки)
  • Инъекция поля : Потребитель использует конструктор без аргументов. Не существует допустимого способа установить состояние объекта. Единственный вариант — использовать Reflection для установки приватных полей.

Слишком много полей экземпляра

Давайте рассмотрим случай с Объектами, имеющими 6, 7 или более полей. Что происходит, когда вы используете приведенные выше примеры с большим количеством полей.

Инъекция поля : все еще выглядит лучше и читабельнее. Часть зависимости отделена в одном месте.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
@Component
public class MyClass {
 
    @Autowired private Service1 service1;
    @Autowired private Service2 service2;
    @Autowired private Service3 service3;
    @Autowired private Service4 service4;
    @Autowired private Service5 service5;
    @Autowired private Service6 service6;
    @Autowired private Service7 service7;
    @Autowired private Service8 service7;
     
    //...
    // Business methods
    //
}

Инъектор конструктора : Гадкий! Внедрение в конструктор выглядит ужасно. Это также не легко использовать для потребителей.

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
@Component
public class MyClass {
 
    private Service1 service1;
    private Service2 service2;
    private Service3 service3;
    private Service4 service4;
    private Service5 service5;
    private Service6 service6;
    private Service7 service7;
    private Service8 service7;
 
    @Autowired
    public MyClass(Service1 service1, Service2 service2, Service3 service3, Service4 service4, Service5 service5, Service6 service6, Service7 service7, Service8 service71) {
        this.service1 = service1;
        this.service2 = service2;
        this.service3 = service3;
        this.service4 = service4;
        this.service5 = service5;
        this.service6 = service6;
        this.service7 = service7;
        this.service7 = service71;
    }
 
 
//...
    // Business methods
    //
}

Сеттер Инъекция : Плохо. Он добавил 8 дополнительных методов экземпляра только для настройки зависимости.

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@Component
public class MyClass {
 
    private Service1 service1;
    private Service2 service2;
    private Service3 service3;
    private Service4 service4;
    private Service5 service5;
    private Service6 service6;
    private Service7 service7;
    private Service8 service7;
 
    @Autowired
    public void setService1(Service1 service1) {
        this.service1 = service1;
    }
 
    @Autowired
    public void setService2(Service2 service2) {
        this.service2 = service2;
    }
 
    @Autowired
    public void setService3(Service3 service3) {
        this.service3 = service3;
    }
 
    @Autowired
    public void setService4(Service4 service4) {
        this.service4 = service4;
    }
 
    @Autowired
    public void setService5(Service5 service5) {
        this.service5 = service5;
    }
 
    @Autowired
    public void setService6(Service6 service6) {
        this.service6 = service6;
    }
 
    @Autowired
    public void setService7(Service7 service7) {
        this.service7 = service7;
    }
 
    @Autowired
    public void setService7(Service8 service7) {
        this.service7 = service7;
    }
 
    //...
    // Business methods
    //
}

Должны ли мы даже рассмотреть «слишком много полей экземпляров»?

С проверкой Too Many Instance Fields мы обнаружили, что Field Injection является лучшим. Реальный вопрос заключается в том, должны ли мы уделять внимание проблеме слишком большого количества полей?

Ответ — нет.
Мы все любим и следуем принципу единой ответственности . Если ваш класс зависит от слишком многих вещей, это признак того, что дизайн не прав. С лучшими проектами вы не увидите этих проблем. Мы должны препятствовать поддержке плохих дизайнерских дел. Следовательно, мы не будем придавать значение случаю «Слишком много полей экземпляров».

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

Вывод

Исходя из приведенных выше примеров кода и фактов, становится ясно, что внедрение на основе зависимостей конструкции всегда лучше во всех случаях. Даже если мы посмотрим на наш класс вне перспективы Spring Dependency Injection, Constructor Injection по-прежнему остается лучшим вариантом.

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

Удачного кодирования!

См. Оригинальную статью здесь: Spring Inpendency Injection — Field vs Setter vs Constructor Injection

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