Dependency Injection (DI) là design pattern quan trọng trong Java. Trước đó, người ta gọi là Inversion of Control (IoC). DI là nền tảng đầu tiên, căn bản để xây dựng nên Spring Framework (được chống lưng bởi Pivotal), Guice (được chống lưng bởi Google) [1].
VÍ DỤ MINH HỌA DEPENDENCY INJECTION BỞI JAVA THUẦN
Các ví dụ sau đây dựa trên ví dụ minh hoạ của Phil Webb [2] trong khoá học Building Microservices with Spring Boot 2.0 (có đôi chút chỉnh sửa lại). Tạo class CreditCard.java , đó là thực thể (entity) thẻ tín dụng, gồm các thuộc tính
+ id: Số định danh
+ creditCardHolder: Họ và tên chủ thẻ tín dụng
+ creditCardNumber: Số thẻ tín dụng
+ ccv: 3 chữ số bảo mật, Nếu ban có 1 chiếc thẻ thanh toán quốc tế MasterCard hoặc VisaCard, bạn sẽ nhìn thấy 3 số này ở mặt sau (3 số này là bảo mật, nên giữ kín)
1
2
3
4
5
6
7
8
9
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
|
package dependencyInjectionExample;
public class CreditCard {
Integer id;
Integer creditCardHolder;
Integer creditCardNumber;
String ccv;
public CreditCard() {
}
public CreditCard(Integer id, Integer creditCardHolder, Integer creditCardNumber, String ccv) {
this.id = id;
this.creditCardHolder = creditCardHolder;
this.creditCardNumber = creditCardNumber;
this.ccv = ccv;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getCreditCardHolder() {
return creditCardHolder;
}
public void setCreditCardHolder(Integer creditCardHolder) {
this.creditCardHolder = creditCardHolder;
}
public Integer getCreditCardNumber() {
return creditCardNumber;
}
public void setCreditCardNumber(Integer creditCardNumber) {
this.creditCardNumber = creditCardNumber;
}
public String getCcv() {
return ccv;
}
public void setCcv(String ccv) {
this.ccv = ccv;
}
}
|
Tạo class Order, thể hiện thực thể (entity) đơn đặt hàng. Một đơn đặt hàng có các thuộc tính
+ id: Số định danh (mã) đơn hàng
+ amount: Số tiền/Giá trị đơn hàng (hoá đơn)
+ note: Ghi chú
1
2
3
4
5
6
7
8
9
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
|
package dependencyInjectionExample;
import java.math.BigDecimal;
public class Order {
Integer id;
BigDecimal amount;
String note;
public Order() {
}
public Order(Integer id, BigDecimal amount, String note) {
this.id = id;
this.amount = amount;
this.note = note;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
|
Có class chứa phương thức để xử lý thanh toán, tác động vào tài khoản thẻ tín dụng của bạn dựa trên số thẻ và số tiền chi tiêu:
1
2
3
4
5
6
7
8
9
10
11
|
package dependencyInjectionExample;
import java.math.BigDecimal;
public class CreditCardProcessor {
public void takePayment(CreditCard creditCard, BigDecimal amount) {
System.out.println(“Sent from “ + creditCard.getCreditCardNumber() + ” “ + amount + ” money.”);
}
}
|
Có class để hiện thực hoá design pattern có tên Dependency Injection, có 2 phương thức phổ biến nhất để khai thác mô hình dependency injection là:
+ Dựa trên method constructor (*)
+ Dựa trên method setter
Ở đây chúng ta sử dụng (*) trong class OrderService
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package dependencyInjectionExample;
public class OrderService {
private CreditCardProcessor creditCardProcessor;
public OrderService(CreditCardProcessor creditCardProcessor){
this.creditCardProcessor = creditCardProcessor;
}
public void placeOrder(Order order, CreditCard creditCard){
this.creditCardProcessor.takePayment(creditCard, order.getAmount());
}
}
|
Như vậy, chúng ta làm 2 việc sau
+ khởi tạo một instance (object) của class OrderService
+ khởi tạo việc xử lý một đơn hàng và gọi đến phương thức thanh toán tác động đến thẻ tín dụng bằng phương thức placeOrder, (gọi được phương thức này sau khi khởi tạo instance (object) của class CreditCardProcessor)
bằng kỹ thuật Dependency Injection (tạm dịch là “Chèn phụ thuộc”).
VÍ DỤ MINH HOẠ DEPENDENCY BỞI SPRING FRAMEWORK
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package dependencyInjectionExample;
import java.sql.Connection;
public class OnlineCreditCardProcessor {
Connection connection;
public OnlineCreditCardProcessor(Connection connection) {
this.connection = connection;
}
}
|
và
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package dependencyInjectionExample;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.sql.Connection;
@Configuration
public class MyConfig {
@Bean
public OnlineCreditCardProcessor creditCardProcessor(Connection connection) {
return new OnlineCreditCardProcessor(connection);
}
}
|
LỢI ÍCH CỦA DEPENDENCY INJECTION
+ Phân tách được sự phụ thuộc. Khi ứng dụng ở quy mô nhỏ, kiến trúc đơn giản vẫn được. Nhưng khi ứng dụng Java ở quy mô lớn (có hàng trăm, hàng nghìn class, sử dụng nhiều thư viện nội bộ và bên ngoài) gọi tham chiếu lẫn nhau, kiến trúc cần sự tinh tế/khoa học, đó là lúc nên nên dùng Dependency Injection.
+ Nhờ sự phân tách phụ thuộc (tham chiếu), dó đó ứng dụng Java có thể viết unit test (JUnit test, TestNG, v.v..) dễ dàng.
+ Nhờ có sự phân tách, nhờ dễ unit test, mà ứng dụng Java dễ bảo trì, dễ nâng cấp, dễ bổ sung tính năng.
DEPENDENCY LÀ MÔ HÌNH/PHƯƠNG THỨC (DESIGN PATTERN) LẬP TRÌNH, KHÔNG LỆ THUỘC VÀO NGÔN NGỮ LẬP TRÌNH
– Nếu bạn không phải là lập trình viên Java, có dùng Dependency Injection không?
– Có. Là lập trình viên PHP, bạn sẽ thấy Dependency Injection trong Zend Framework [3] [4]. Là lập trình viên Python, bạn sẽ thấy Dependency Injection trong Pinject [5], v.v.. Và nếu bạn không muốn sử dụng Dependency Injection dựng sẵn bởi các framework, bạn có thể tự lập trình theo mô hình này.
[1] https://github.com/google/guice
[2] https://spring.io/team/pwebb
[3] https://github.com/zendframework/zend-di
[4] https://framework.zend.com/manual/2.4/en/tutorials/quickstart.di.html
[5] https://github.com/google/pinject
Đỗ Như Vý
Software developer
Dependency Injection,
Inversion of Control,
java,
php,
Python,
Spring,
Spring framework,