2009-10-16 33 views
39

Tôi đã có một cảm giác nhất định trong vài ngày qua rằng việc tiêm phụ thuộc thực sự nên được gọi là "Tôi không thể quyết định được" -pattern. Tôi biết điều này nghe có vẻ ngớ ngẩn, nhưng thực sự đó là lý do đằng sau lý do tại sao tôi nên sử dụng Dependency Injection (DI). Thường thì người ta nói rằng tôi nên sử dụng DI, để đạt được một mức độ cao hơn của khớp nối lỏng lẻo, và tôi nhận được một phần đó. Nhưng thực sự ... làm thế nào để tôi thường xuyên thay đổi cơ sở dữ liệu của tôi, một khi sự lựa chọn của tôi đã giảm trên MS SQL hoặc MySQL .. Rất hiếm khi phải không?Khi nào sử dụng Dependency Injection

Có ai có một số lý do rất thuyết phục tại sao DI là con đường để đi không?

+3

Tôi thích tất cả các lý do của bạn cho đến nay ... Tôi hiểu rằng phần lớn các lập trình viên dày dạn kinh nghiệm là "nhận" DI. Theo tôi hiểu, DI là về chất lượng. Chúng tôi, là người lập trình, muốn tạo ra mức phần mềm cao nhất mà chúng tôi có thể - và thử nghiệm nó giúp ích. Tôi đã viết ALOT mã trong những năm qua, và tôi rất vui khi nói rằng 10 năm trước, hơn 50% số đó vẫn đang chạy .. và không có DI. Có lẽ điều đó giúp bạn hiểu tại sao tôi lại dành chút thời gian cho DI? – CodeMonkey

+0

Rõ ràng DI là mới tương đối nói. Vì vậy, tất nhiên bạn có thể viết phần mềm chất lượng cao mà không có nó - nhưng với sự tiến bộ của những thứ như khuôn khổ kiểm tra và TDD, DI có thể làm cho nó dễ dàng hơn nhiều để viết các bài kiểm tra cũng như viết mã được duy trì cho tương lai (khớp nối). – digiarnie

Trả lời

44

Hai từ, kiểm tra đơn vị.

Một trong những lý do thuyết phục nhất cho DI là cho phép kiểm tra đơn vị dễ dàng hơn mà không cần phải nhấn vào cơ sở dữ liệu và lo lắng về việc thiết lập dữ liệu 'thử nghiệm'.

+2

Vì vậy, bạn đang nói về de-coupling cơ sở dữ liệu, và "giả mạo nó", bằng cách sử dụng một số đối tượng giả thay vì thay đổi DB của tôi trong bài kiểm tra đơn vị của tôi ... hmm ... âm thanh như một đối số hợp lý thực sự !! – CodeMonkey

+0

Nhưng vì nó là một cơ sở dữ liệu thử nghiệm, có thực sự quan trọng là cơ sở dữ liệu của tôi được cập nhật không ?? – CodeMonkey

+5

Các thử nghiệm của bạn sẽ chạy nhanh hơn rất nhiều mà không cần phải nhấn vào một cơ sở dữ liệu thực sự. Thêm vào đó, khi bạn đang thử nghiệm cho các trường hợp cụ thể, bạn sẽ dễ dàng hơn trong việc thiết lập những trường hợp cụ thể trong một đối tượng giả và phải lo lắng nếu cơ sở dữ liệu thử nghiệm của bạn ở trạng thái chính xác hay không. –

1

Ngoài khớp nối lỏng lẻo, thử nghiệm bất kỳ loại nào đạt được dễ dàng hơn nhiều nhờ DI. Bạn có thể đặt thay thế một phụ thuộc hiện có của một lớp đang được thử nghiệm với một mô hình, một giả hoặc thậm chí là một phiên bản khác. Nếu một lớp được tạo ra với các phụ thuộc của nó được trực tiếp khởi tạo, nó thường có thể khó hoặc thậm chí không thể "bung" chúng ra nếu được yêu cầu.

+0

Bạn có thể xây dựng trên các thuật ngữ "sơ khai" và "giả" ... Tôi giả sử "giả" là cái mà tôi gọi là "giả" -objects – CodeMonkey

+2

Bằng cách tôi chỉ đề cập đến việc thay thế bất kỳ sự phụ thuộc nào đó thử nghiệm. Bởi giả tôi có nghĩa là bằng cách sử dụng một thư viện như jmock hoặc mockito (nếu bạn đang sử dụng java của khóa học) để tạo ra một proxy, nơi bạn tuyên bố kỳ vọng về đối tượng "giả". Bạn cũng có thể tạo một phiên bản giả của một lớp bằng cách thực hiện giao diện của phụ thuộc. – digiarnie

+0

Khi u giả lập đối tượng, bạn có đăng ký nó trong sổ đăng ký di hoặc chỉ cần truyền đối tượng giả vào? thông qua hàm tạo chẳng hạn. – liang

5

Trong khi tôi bán đồng ý với bạn với ví dụ DB, một trong những điều lớn mà tôi thấy hữu ích khi sử dụng DI là giúp tôi kiểm tra lớp tôi xây dựng trên cơ sở dữ liệu.

Đây là ví dụ ...

Bạn có cơ sở dữ liệu của mình.

Bạn có mã của bạn có thể truy cập cơ sở dữ liệu và trả về đối tượng

Bạn có các đối tượng lĩnh vực kinh doanh mà phải mất đối tượng mục trước và làm một số logic với họ.

Nếu bạn hợp nhất quyền truy cập dữ liệu với logic miền doanh nghiệp của mình, đối tượng miền của bạn có thể trở nên khó kiểm tra. DI cho phép bạn tiêm các đối tượng truy cập dữ liệu của riêng bạn vào miền của bạn để bạn không phụ thuộc vào cơ sở dữ liệu để thử nghiệm hoặc có thể trình diễn (chạy bản demo nơi một số dữ liệu được lấy từ xml thay vì cơ sở dữ liệu).

Tóm tắt các thành phần và khung bên thứ 3 như thế này cũng sẽ giúp bạn.

Ngoài ví dụ thử nghiệm, có một vài nơi DI có thể được sử dụng thông qua phương pháp Thiết kế theo Hợp đồng. Bạn có thể tìm thấy nó thích hợp để tạo ra một công cụ xử lý các loại gọi các phương thức của các đối tượng mà bạn đang tiêm vào nó. Trong khi nó có thể không thực sự "xử lý nó" nó chạy các phương pháp có thực hiện khác nhau trong từng đối tượng bạn cung cấp.

Tôi đã xem ví dụ về điều này trong đó mỗi đối tượng miền doanh nghiệp có chức năng "Lưu" được gọi sau khi được tiêm vào bộ xử lý. Bộ xử lý đã sửa đổi thành phần với thông tin cấu hình và Lưu xử lý trạng thái chính của đối tượng. Về bản chất, DI bổ sung cho việc thực hiện phương pháp đa hình của các đối tượng phù hợp với Giao diện.

6

Thậm chí nếu bạn không thay đổi cấu trúc chương trình của mình trong giai đoạn phát triển, bạn sẽ tìm thấy bạn cần truy cập một số hệ thống con từ các phần khác nhau của chương trình. Với DI mỗi lớp học của bạn chỉ cần yêu cầu dịch vụ và bạn không phải tự cung cấp tất cả các hệ thống dây điện.Điều này thực sự giúp tôi tập trung vào sự tương tác của mọi thứ trong thiết kế phần mềm chứ không phải là "ai cần mang theo những gì xung quanh vì ai đó cần nó sau này".

Ngoài ra, nó cũng chỉ tiết kiệm rất nhiều công việc viết mã soạn sẵn. Tôi có cần một singleton không? Tôi chỉ cần cấu hình một lớp là một. Tôi có thể thử nghiệm với một "singleton" như vậy không? Có, tôi vẫn có thể (vì tôi chỉ CONFIGURED nó tồn tại chỉ một lần, nhưng thử nghiệm có thể nhanh chóng triển khai thay thế). Tuy nhiên, bằng cách này trước khi tôi sử dụng DI tôi đã không thực sự hiểu giá trị của nó, nhưng cố gắng nó là một mắt mở thực sự cho tôi: thiết kế của tôi là rất nhiều đối tượng theo định hướng như họ đã được trước đây. Nhân tiện, với ứng dụng hiện tại tôi KHÔNG kiểm tra đơn vị (xấu, xấu cho tôi) nhưng tôi STILL không thể sống với DI nữa. Việc di chuyển mọi thứ trở nên dễ dàng hơn nhiều và giữ các lớp học nhỏ và đơn giản.

+1

+1 để đề cập đến cách khung DI/IoC Container có thể thay thế mẫu Singleton độc ác! – TrueWill

+0

Hầu hết các khuôn khổ DI tôi thấy có ít nhất 2000 dòng mã, mà có vẻ như rất nhiều mã. Ngoài ra, có vẻ như bạn không thể sử dụng khung làm việc mà không sửa đổi mã hiện có. Theo kinh nghiệm của bạn, thật dễ dàng để trao đổi một khuôn khổ DI cho một khuôn khổ khác? – Boon

+0

@TrueWill Tại sao Singleton ác trong khi phiên bản DI của nó, tốt? – zehelvion

4

Tiêm phụ thuộc cho phép bạn kiểm tra các đơn vị mã cụ thể một cách riêng biệt.

Giả sử tôi có một lớp Foo ví dụ: có thể hiện của một lớp Bar trong hàm tạo của nó. Một trong các phương thức trên Foo có thể kiểm tra xem giá trị thuộc tính của Bar là một trong các phương thức cho phép xử lý Bar khác.

public class Foo 
{ 
    private Bar _bar; 

    public Foo(Bar bar) 
    { 
     _bar = bar; 
    } 

    public bool IsPropertyOfBarValid() 
    { 
     return _bar.SomeProperty == PropertyEnum.ValidProperty; 
    } 
} 

Bây giờ giả sử rằng Bar được khởi tạo và thuộc tính được đặt thành dữ liệu từ một số nguồn dữ liệu trong hàm tạo của nó. Làm thế nào tôi có thể đi về thử nghiệm phương pháp IsPropertyOfBarValid() của Foo (bỏ qua thực tế rằng đây là một ví dụ vô cùng đơn giản)? Vâng, Foo phụ thuộc vào trường hợp của Bar được truyền vào hàm tạo, do đó phụ thuộc vào dữ liệu từ nguồn dữ liệu mà thuộc tính của nó được đặt thành. Những gì chúng tôi muốn làm là có cách nào đó để tách biệt Foo khỏi các tài nguyên mà nó phụ thuộc để chúng tôi có thể kiểm tra nó trong sự cô lập

Đây là nơi mà Dependency Injection đi vào. Những gì chúng tôi muốn là có một số cách để giả mạo Ví dụ của Bar được chuyển đến Foo sao cho chúng tôi có thể kiểm soát các thuộc tính được đặt trên giả Bar và đạt được những gì chúng tôi đặt ra để thực hiện, kiểm tra xem việc thực hiện IsPropertyOfBarValid() có làm như thế nào không. giá trị khác.

Có hai loại đối tượng giả, Mocks và Stubs. Sơ khai cung cấp đầu vào cho ứng dụng đang được kiểm tra để kiểm tra có thể được thực hiện trên một thứ khác. Mocks mặt khác cung cấp đầu vào cho thử nghiệm để quyết định pass \ fail.

Martin Fowler has a great article on the difference between Mocks and Stubs

1

Tôi nghĩ rằng DI là giá trị sử dụng khi bạn có rất nhiều dịch vụ/linh kiện mà hiện thực phải được lựa chọn trong thời gian chạy dựa trên cấu hình bên ngoài. (Lưu ý rằng cấu hình như vậy có thể dưới dạng một tệp XML hoặc kết hợp các chú thích mã và các lớp riêng biệt; hãy chọn những gì thuận tiện hơn.)

Nếu không, tôi chỉ đơn giản sử dụng một ServiceLocator, nhiều "nhẹ" hơn và dễ hiểu hơn toàn bộ khuôn khổ DI.

Để kiểm tra đơn vị, tôi thích sử dụng API giả mạo có thể giả lập các đối tượng theo yêu cầu, thay vì yêu cầu chúng được "tiêm" vào đơn vị được thử nghiệm từ thử nghiệm. Đối với Java, một thư viện như vậy là của riêng tôi, JMockit.

+0

+1 để đề cập đến servicelocator. Tôi nghĩ đôi khi DI có vẻ quá mức cần thiết khi mọi người chỉ sử dụng khía cạnh "vị trí dịch vụ" của nó. –

0

Tôi vừa mới hiểu tối nay. Đối với tôi, tiêm phụ thuộc là một phương pháp để khởi tạo các đối tượng đòi hỏi nhiều tham số để làm việc trong một ngữ cảnh cụ thể.

Khi nào bạn nên sử dụng tiêm phụ thuộc? Bạn có thể sử dụng tiêm phụ thuộc nếu bạn instanciate một cách tĩnh một đối tượng. Ví dụ, nếu bạn sử dụng một lớp có thể chuyển đổi các đối tượng thành tệp XML hoặc tệp JSON và nếu bạn chỉ cần tệp XML. Bạn sẽ phải instanciate đối tượng và cấu hình rất nhiều điều nếu bạn không sử dụng tiêm phụ thuộc.

Khi nào bạn không nên sử dụng thuốc tiêm dư thừa? Nếu một đối tượng được instanciated với các thông số yêu cầu (sau khi một hình thức nộp đơn), bạn không nên sử dụng tiêm depandancy vì đối tượng không instanciated một cách tĩnh.

+0

Tôi đã hỏi câu hỏi này nhiều năm trước, và tôi đã học được rất nhiều từ đó. Những gì bạn đang mô tả sẽ được giải quyết tốt bằng cách sử dụng một container IoC, và tiêm đối tượng đã tạo bằng cách sử dụng DI. Vì vậy, ví dụ, bạn cấu hình đối tượng "phức tạp" của bạn trong registry của IoC container, và "yêu cầu" một thể hiện của cái mà bạn tiêm vào mã mà bạn cần nó. Tôi đồng ý rằng đó cũng là một lý do hợp lệ để sử dụng DI. – CodeMonkey

9

DI rất hữu ích cho việc tách hệ thống của bạn. Nếu tất cả những gì bạn đang sử dụng là phân tách việc triển khai cơ sở dữ liệu từ phần còn lại của ứng dụng, thì ứng dụng của bạn khá đơn giản hoặc bạn cần phân tích nhiều hơn về miền vấn đề và khám phá những thành phần nào trong miền vấn đề của bạn có nhiều khả năng thay đổi nhất và các thành phần trong hệ thống của bạn có lượng khớp nối lớn.

DI hữu ích nhất khi bạn hướng đến việc sử dụng lại mã, tính linh hoạt và mạnh mẽ cho các thay đổi trong miền sự cố của bạn.

Mức độ liên quan của dự án của bạn phụ thuộc vào tuổi thọ dự kiến ​​của mã của bạn. Tùy thuộc vào loại công việc bạn đang làm không tái sử dụng từ một dự án tiếp theo cho phần lớn mã bạn đang viết thực sự có thể khá chấp nhận được.

Ví dụ về sử dụng DI là tạo ứng dụng có thể được triển khai cho nhiều khách hàng sử dụng DI để chèn tùy chỉnh cho ứng dụng khách, cũng có thể được mô tả là mẫu Chiến lược GOF. Nhiều người trong số các mô hình GOF có thể được tạo điều kiện với việc sử dụng một khuôn khổ DI.

DI liên quan nhiều hơn đến việc phát triển ứng dụng doanh nghiệp, trong đó bạn có một lượng lớn mã, yêu cầu kinh doanh phức tạp và kỳ vọng (hoặc hy vọng) rằng hệ thống sẽ được duy trì trong nhiều năm hoặc nhiều thập kỷ.

+0

Nó cũng hữu ích trong quá trình phát triển nhanh nếu bạn tìm kiếm sự linh hoạt (vì bạn muốn tiến hành thử nghiệm). Bạn có thể dễ dàng kết nối các khung nhìn khác nhau, cấu trúc dữ liệu, các menu, các lược đồ điều khiển và những gì không. Về cơ bản, (nếu tôi hiểu và sử dụng nó một cách chính xác), cho phép bạn quản lý "các phụ thuộc" một cách linh hoạt và có tổ chức hơn với ít tiếng ồn của mã lò hơi hơn. Tất nhiên nó có thể bị lạm dụng và bằng cách nào đó làm cho mã phức tạp hơn. – zehelvion

Các vấn đề liên quan