2011-06-17 37 views
6

Tôi đã đọc về tiêm phụ thuộc, và tôi hiểu khái niệm cơ bản là một phương pháp sẽ nhận được những gì nó cần từ người gọi của nó chứ không phải là tạo ra các vật phẩm đó. Kết quả là, các toán tử new bị loại bỏ khỏi phương thức gần như hoàn toàn (một số đối tượng cơ bản nhất định sẽ được miễn, dĩ nhiên - một ví dụ về điều này tôi tìm thấy là những thứ như StringBuilder s có vẻ như sẽ mất trí phải chuyển vào) .Khi sử dụng tiêm phụ thuộc, tất cả các toán tử mới sẽ đi đâu?

Câu hỏi của tôi nghe có vẻ đơn giản, nhưng tôi nghi ngờ câu trả lời thực sự khá phức tạp: Tất cả các toán tử new hoạt động ở đâu?

Câu trả lời có vẻ đơn giản lúc đầu: toán tử new chỉ được đẩy tới phương thức gọi phương thức cần đối tượng. Tuy nhiên, vấn đề với phương pháp gọi này có thể cũng đang được kiểm tra và do đó new bị đẩy lên từ phương thức gọi đến phương thức gọi cho đến khi bạn nhận được một phương pháp gốc (mà tại thời điểm này dường như không thể tin được) số lượng các đối tượng khiêu dâm để sử dụng tại các điểm khác nhau trong ngăn xếp cuộc gọi. Tình hình trở nên phức tạp hơn khi bạn xem xét rằng phương pháp gốc đó là gốc rễ của nhiều phương thức khác nhau, và do đó sẽ cần phải tạo ra các đối tượng cho mọi khả năng. Điều này cũng tạo ra một vấn đề hiệu suất vì bạn sẽ nhanh chóng được trái với một số lượng lớn các đối tượng mà không bao giờ thực sự được sử dụng, nhưng phải được instantiated anyway "chỉ trong trường hợp". Một điều khá rõ ràng đối với tôi rằng tôi đã bỏ lỡ một số phần quan trọng của kiến ​​thức mà là như vậy rõ ràng cho các nhà phát triển khác mà không ai nghĩ rằng để mô tả nó trong một bài đăng trên blog. Tuy nhiên, tôi rõ ràng không thể biết những gì tôi không biết, vì vậy tôi khiêm nhường hỏi rằng tôi được cho vào bí mật: Nơi nào tất cả các nhà khai thác new đi?

Tôi nên đề cập rằng tôi đang phát triển với PHP, vì vậy mọi yêu cầu đều bắt đầu tại cùng một điểm và có vẻ như "phương pháp" gốc đó trong index.php sẽ cần phải bao gồm mọi thứ mà ứng dụng có thể làm, để đảm bảo nó cung cấp một đối tượng cho mọi thứ mà nó sẽ thực hiện theo yêu cầu hiện tại. Một lần nữa, có một sự hiểu lầm cơ bản ở đây, và tôi thực sự thích sửa nó.

+1

Xem điều này có giúp ích: http://misko.hevery.com/2008/09/10/where-have-all-the-new-operators-gone/ –

Trả lời

1

Tính phụ thuộc Tiêm thường được sử dụng trong các ứng dụng MVC. Trong trường hợp đó, "new", như bạn gọi nó, thường đi vào lớp Trình điều khiển.

Khi gọi Mô hình, Trình điều khiển giải thích các phụ thuộc và cung cấp cho Mô hình, sau đó gọi các phương thức kinh doanh mà Mô hình tiếp xúc.

Nhưng đừng nghĩ DI là về "xóa new s". Đó là về tách. Các lớp học ít instanciate (và do đó "biết") các lớp khác, ít hơn có thể bị tổn hại bằng cách thay đổi trong các classeS khác.

Mục đích khác là làm cho thử nghiệm dễ dàng hơn. Nếu bạn có phương thức cần soạn và gửi thư, thật khó để kiểm tra xem thư có được soạn chính xác hay không. Tuy nhiên, nếu bạn loại bỏ sự phụ thuộc của việc gửi thư, từ lớp này sang lớp khác, và chỉ đưa ra một đối tượng có thể gửi thư đến phương thức này, khi bạn viết test, thay vì cho phương thức này một đối tượng có thể thực sự gửi thư, bạn sẽ cung cấp cho phương thức này một đối tượng chỉ có thư gửi giả mạo. Bạn có thấy điểm không?

+0

Giả sử tôi đang xây dựng khung đồ chơi riêng của mình một kinh nghiệm học tập. Tôi có nên xem xét "BeginRequest -> Controller" vì nó là đơn vị kiểm thử của riêng nó, và "Controller -> LeafMethods" là một đơn vị riêng biệt, và sử dụng nó như một điểm phân giới cho các lô thử nghiệm đơn vị khác nhau? – AgentConundrum

+0

Tôi hiểu khía cạnh thử nghiệm/ghép nối (quan tâm của tôi trong việc thử TDD là điều đã dẫn tôi đến đây để bắt đầu). Tôi cũng không nói DI là về * loại bỏ * các toán tử 'mới', chỉ rằng nó yêu cầu chúng được di chuyển lên chuỗi. Đối tượng gửi thư của bạn cần một thứ để gửi thư, và bạn tách rời nó khỏi thứ gửi thư bằng cách truyền đối tượng cho một bưu phẩm. Quan điểm của tôi đơn giản là người gửi thư phải đến từ đâu đó phía trên đối tượng đó, và tôi chỉ đang cố gắng tìm ra nơi. Xin lỗi nếu điều này là sắp tắt khủng khiếp noobish/ngây thơ; Tôi chỉ đang cố học. :) – AgentConundrum

3

Khá hiển nhiên - nhà điều hành new đã chuyển đến vùng chứa DI, khi tất cả các sự kiện xảy ra.

Cũng không có bất kỳ vấn đề hiệu suất nào, bởi vì dịch vụ được khởi tạo theo yêu cầu - khi bạn yêu cầu chúng lần đầu tiên.

Để phát triển bằng PHP, tôi đề nghị bạn xem xét Symfony Framework thực hiện DI rất tốt và đó là một ví dụ về kiến ​​trúc hoàn hảo và tinh khiết.

+0

Tôi nên làm rõ rằng tôi chủ yếu nói về việc xây dựng tiêm ở đây. Phải thừa nhận rằng tôi không biết nhiều về DI container, vì chúng dường như xấu xí với tôi - về bản chất là một biến "toàn cầu" lớn/singleton hoạt động giống như ma thuật với phương pháp giả định container ở trạng thái phù hợp để làm việc, thay vì được thông qua phụ thuộc trực tiếp. Bạn cũng nói rằng vùng chứa này cần phải được mã hóa để có thể tạo bất kỳ chuỗi instantiation nào cần thiết, mà âm thanh vẫn rất giống với "phương thức gốc" của tôi được mô tả trong câu hỏi. (Xin lỗi nếu tôi ngây thơ với điều này, nó chỉ vì tôi.) – AgentConundrum

+0

Về chỉnh sửa của bạn liên quan đến Symphony - Tôi không nghĩ rằng nó cần thiết để thêm ở đây, nhưng tôi cũng đang cố gắng để cuộn đồ chơi của riêng tôi "khuôn khổ" ở đây ngoài các ứng dụng nhỏ mà sẽ ngồi trên đầu trang của nó. Mục tiêu của tôi ở đây là tìm hiểu a) cách các khung làm việc và b) cách DI được áp dụng đúng cách. Một câu trả lời của "chỉ cần sử dụng này, nó đã làm tất cả mọi thứ cho bạn" không giúp đỡ, vì tôi sẽ không tìm hiểu bất cứ điều gì. Tôi vẫn còn là một nhà phát triển cơ sở, và tôi đang cố gắng khắc phục điều đó bằng cách bị dơ tay. Tôi chỉ gặp vấn đề trong việc hiểu các khía cạnh nhất định của các khái niệm cũng như tôi muốn. – AgentConundrum

+0

Tôi đề nghị bạn đọc loạt bài này từ Miško Hevery: http://misko.hevery.com/code-reviewers-guide/ Ông mô tả DI là gì và cách bạn nên áp dụng nó một cách chính xác. –

-2

DI thường được sử dụng song song với Vùng chứa IOC (khi tỷ lệ của ứng dụng vượt quá ngưỡng nhất định). Các thùng chứa được cấu hình sao cho chúng có thể yêu cầu dịch vụ cho một kiểu/giao diện cụ thể và trả về các đối tượng được xây dựng hoàn chỉnh (với các phụ thuộc bắt buộc).

Vì vậy, thay vì thực hiện new ConcreteType(), bạn hỏi vùng chứa container.Get<Interface/Type>().

Điều đó nói rằng, vì tôi đã đọc các nhận xét cho biết bạn vừa mới bắt đầu, tôi khuyên bạn không nên cuộn Khung DI của riêng mình (đó là thời gian chìm chung). Sử dụng và nghiên cứu mã cho các thư viện DI chức năng hiện có như MEF/Unity/bất kỳ thư viện nào khác.

+1

Er, cẩn thận, bạn dường như ngụ ý người ta nên sử dụng các DI container như là một định vị dịch vụ, tức là thay thế tất cả 'new' với 'container.Get' s. Có thể muốn chỉnh sửa điều đó không? – Domenic

+0

@Domenic - Tôi không thấy sai lầm. Nếu tôi đang sử dụng một vùng chứa DI, tôi sẽ sử dụng nó để tạo ra tất cả các vai trò công khai (ngoại trừ các phụ thuộc lớp bên trong sẽ không bao giờ thay đổi cho một đối tượng cụ thể). – Gishu

+2

@Gishu Tôi nghĩ rằng điểm Domenic đang cố gắng tạo ra là nếu bạn đang sử dụng container trong thời trang đó, bạn đang làm Service Location, chứ không phải Dependency Injection. Điều đó thường được cho là lạm dụng một container IoC, bởi vì nó bỏ lỡ điểm đảo ngược kiểm soát. –

5

Bạn đã nhận được rất nhiều điều đúng: tất cả đều kết thúc bằng số thành phần gốc của bạn. Xem this interview with Mark Seeman, gần phía dưới, để giải thích tại sao đây là một thực hành tốt và quan trọng.

Ngoài ra lưu ý: tiêm phụ thuộc có nghĩa là cho các dịch vụ, không phải thực thể hoặc đối tượng giá trị. Vì vậy, ví dụ: tiêm IUserRepository có ý nghĩa, nhưng IUser không quá nhiều --- và chắc chắn không phải là StringBuilder s. Điều đó có thể giúp làm sáng tỏ mọi thứ, theo ánh sáng của cha mẹ bạn về các loại nguyên thủy hơn: sự phân chia không thực sự nguyên thủy như thế nào, mà đúng hơn là vai trò của chúng trong hệ thống.

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