Saturday, May 31, 2014

Dependency Injection (DI) và Inversion of Control (IOC)

Dependency Injection (DI) và Inversion of Control (IOC)

DI là gì?

Bài viết này giới thiệu một sự tổng quan ở mức cao về Dependency Injection (DI). Mục đích của bài viết nhằm giới thiệu khái niệm tổng quát về DI cho những nhà phát triển ít kinh nghiệm cũng như cách sử chúng trong những DI container khác nhau như thế nào.
Dependency Injection (DI) hay Inversion of Control (IOC) ?

Nhiều tài liệu hiện nay thường đề cập đến cùng một mô hình thiết kế như Dependency Injection hoặc Inversion of Control. Tôi ưa thích DI hơn xuất phát từ sự tin tưởng rằng nó là một cái tên rõ ràng hơn. Tôi có thể hình dung nhiều kịch bản mà một người có thể tìm thấy bằng chứng của Inversion of Control, mặc dù kết quả không giống nhau để có thể tập trung vào giải quyết những gì liên quan (chẳng hạn như chuyển từ một ứng dụng console sang một vòng lặp sự kiện Windows). Tuy nhiên bạn thích iOC , bạn có thể thoải mái đọc phần còn lại của bài viết bằng việc thay thế DI với iOC. Kèm theo iOC có nhiều kiểu khác nhau (được gọi ban đầu là kiểu 1, kiểu 2, kiểu 3). Sự khác nhau giữa những kiểu này không hề ảnh hưởng đến phạm vi bài viết và không ăn nhập đến nó.

Cũng nên để ý rằng tôi đã sử dụng thuật ngữ Service mở rộng thông qua bài viết này. Điều này không hề lẫn lộn với Kiến trúc Hướng Dịch vụ (Service Oriented Architectures). Đơn giản chỉ là để dễ dàng hơn trong việc nhận biết được vai trò của “Clients” và “Services” cũng như sự đối ngược của “Client Component” và “Server Component hay Supplier Component”.
Giới thiệu đơn giản về Dependency injection

Kịch bản 1

Bạn làm việc trong một tổ chức mà ở đó, bạn và những người đồng nghiệp thường xuyên đi xa. Thông thường, bạn di chuyển bằng máy bay và mỗi lần bạn cần phải đón một chuyến bay, bạn sắp xếp đón tiếp bằng taxi. Bạn biết về đại lý vé máy bay nơi mà bán vé máy bay,và đại lý taxi nơi taxi đón bạn tai sân bay. Bạn biết số điện thoại của những nơi đó, bạn nắm chắc về các hoạt động thương thảo để đặt vé cần thiết.

Như vậy, kế hoạch chuyến đi xa của bạn thông thường phải như sau:

* Quyết định đích đến và yêu cầu ngày giờ .

* Gọi cho đại lý vé máy bay và thông báo các thông tin vần thiết để đăng ký vé máy bay.

* Gọi cho đại lý taxi, yêu cầu cho xe tới đón đúng giờ chuyến bay và thông báo thời gian cư trú của bạn (đại lý taxi lần lượt phải liên lạc với đại lý vá máy bay để lấy thông tin về chuyến bay, tính toán khoản thời gian chênh lệch giữa thời gian cư trú, đồng thời tính toán thời gian phù hợp để mà sắp xếp taxi đưa đón bạn trong thời gian cư trú).

* Lấy vé, bắt taxi và tiếp tục theo cách đó

Bây giờ, nếu như công ty bạn đột nhiên thay đổi những đại lý đó và họ đưa ra phương thức giao tiếp mới, bạn sẽ phải theo một kịch bản khác.

* Đại lý mới và phương thức liên lạc mới ( toàn bộ mọi giao dịch và liên lạc đều thông qua internet thay thế việc liên lạc qua điện thoại)

* Việc đặt vé được làm thông qua trao đổi được thực hiện thường xuyên ( Dữ liệu thay cho giọng nói ).

Điều đó không khó cho bạn, nhưng có lẽ nhiều đồng nghiệp của bạn sẽ cần sắp đặt lại chúng để có một lịch bản mới. Điều này có thể dẫn tới phải tốn một khoản thời gian lớn trong việc điều chỉnh lại xử lý.

Kịch bản 2

Bây giờ ta hãy nói tới giao thức chỉ có một chút thay đổi. Bạn có một phòng quản lý. Bất cứ khi nào bạn cần đi xa hệ thống tương tác điện thoại phòng quản lý sẽ tự động gọi cho bạn ( mà đã được kết nối với các văn phòng đại diện ). Mục đích đơn giản là xác nhận bạn đến nơi nào, ngày giờ đến để thiết lập chương trình thiết lập câu hỏi. Chuyến bay được đặt cho bạn, sắp xếp các xe taxi cho phù hợp với lịch công việc, và vé được chuyển tới cho bạn.

Bây giờ nếu văn phòng đại diện thay đổi, phòng quản lý sẽ thay đổi cho phù hợp để có thể làm việc với các văn phòng đại diện. Hệ thống tương tác điện thoại có thể thay đổi lại chương trình giao tiếp với các đại diện trên internet. Tuy nhiên bạn và những đồng nghiệp của bạn lại không biết những thay đổi đó. Bạn vẫn tếp tục theo cùng giao thức (vì phòng quản lý đã làm tất cả những gì cần thiết bạn không cần làm bất cứ điều gì khác).
Dependency injection ?

Trong cả hai kịch bản, bạn là khách hàng và bạn phụ thuộc vào những dịch vụ được cung cấp bởi những văn phòng đại diện. Tuy nhiên kịch bản 2 có một vài điểm khác biệt: 

* Bạn không cần biết số điện thoại và văn phòng đại diện nào – phòng quản lý sẽ làm chuyện đó và liên lạc với bạn khi cần thiết.

* Bạn không cần biết chính xác các cuộc đàm thoại diễn ra theo cách thức nào (nói/dữ liệu …) mặc dù bạn phải nhận biết được chuẩn đàm thoại với phòng quản lý

* Những dịch vụ mà bạn dựa vào được cung cấp theo một cách mà bạn không cần phải thay đổi nó khi mà những nhà cung cấp dịch vụ đó thay đổi.

Đó là dependency injection trong “đời sống thực”. Điều này có lẽ trông không giống như bạn hình dung một khoản chi phí cho một mình bản thân bạn – nhưng nếu như bạn hình dung một tổ chức lớn thì việc tiết kiệm là rất đáng kể.
Dependency injection trong phần mềm

Các component phần mềm (Client), thường là một phần của một tập các component với nhau phụ thuộc vào những component khác (Service) hoàn thành trọn vẹn mục đích dự định của chúng. Trong nhiều ngữ cảnh, chúng cần phải biết component nào để giao tiếp, nơi nào để xác định chúng và làm thế nào để giao tiếp với chúng. Khi cách thức mà những dịch vụ có thể được truy cập bị thay đổi, những thay đổi như thế có thể tiềm ẩn yêu cầu rất nhiều client phải thay đổi.
Một cách để cấu trúc mã là đặt các client nhúng tập hợp với việc xác định và/hoặc tạo thực thể các dịch vụ như là một phần của chúng. Một cách khác để cấu trúc mã là có các client công bố sự phụ thuộc của chúng trên các service, và có những phần “mở rộng” của mã nắm bắt nhiệm vụ của việc xác định và/hoặc tạo thực thể các dịch vụ và việc hỗ trợ đơn giản những dịch vụ liên quan đến các client khi cần thiết. Trong phương thức sau cùng, mã client thông thường không yêu cầu được thay đổi khi cách thức xác định một phần mở rộng liên quan thay đổi. Kiểu bổ sung này được xem như một sự bổ sung của Dependency injection và phần mã “mở rộng” liên quan đến trước đó được xử lý riêng hoặc bổ sung sử dụng một trong những DI framework khác nhau.

Những nỗ lực để ánh xạ kịch bản trên cho đặc ngữ thiết kế sẽ chú ý rằng sự tương tự có thể được áp dụng cho ba đặc ngữ thiết kế khác nhau – Dependency injection, Factory và Program cho một Giao tiếp và không phải là một Bổ sung. Ba đặc ngữ thiết kế này thường tương tự nhưng không cần thiết được sử dụng với nhau.

Quy ước trước đây một vài năm là phân chia interface từ implementation. Mẫu thiết kế này thậm chí cho phép che dấu sự phức tạp của các thực thể. Tuy nhiên kỹ thuật “xác định” các dịch vụ thường tách rời với các client. Hơn nữa, một vài phần của phần mềm cũng cần biết những phần phụ thuộc giữa bản thân những dịch vụ khác nhau và vì thế hoàn toàn tuyệt đối phải làm việc liên tục với việc khởi tạo component, và phải chia nhỏ và quản lý các vòng đời của chúng.

Một ví dụ, trong khi đặc tả J2EE sử dụng JNDI như một kỹ thuật để chuẩn hoá kỹ thuật xác định các dẫn xuất đối tượng, chẳng hạn như các bổ sung thường yêu cầu một lượng lớn sự thay đổi mã khi nói các client cần làm việc trong những môi trường đơn giản hơn nhiều mà ở đó JNDI không có sẵn.

Việc sử dụng DI yêu cầu phần mềm chúng ta viết phải công bố các dependency và đặt framework hoặc các container làm việc liên tục với những rắc rối của các thực thể service, khởi tạo, sắp xếp và hỗ trợ các service liên quan đến client được yêu cầu.
Một vài DI Framework

Có một số các framework sẵn có để giúp đỡ các developer. Những framework tôi thấy hữu dụng là: 

Spring Framework: một framework lớn chắc chắn đưa ra một lượng các khả năng khác tách ra từ Dependency injection

PicoContainer: một DI container framework nhỏ nhưng mạnh mẽ

HiveMind: một DI container framework khác.

Xwork: Một framework độc lập thường được sử dụng trong liên kết chung với Webwork

Src sưu tầm: internet

No comments:

Post a Comment