2010-03-24 51 views
9

Tôi đang bắt đầu một dự án mới và thiết lập cơ sở để làm việc. Một vài câu hỏi đã tăng lên và có lẽ tôi sẽ hỏi khá nhiều ở đây, hy vọng tôi sẽ tìm thấy một số câu trả lời.Truy cập vào vùng chứa DI

Bước đầu tiên là xử lý các phụ thuộc cho các đối tượng. Tôi đã quyết định đi với mô hình thiết kế tiêm phụ thuộc, mà tôi có phần mới, để xử lý tất cả điều này cho ứng dụng.

Khi thực sự mã hóa, tôi gặp phải sự cố. Nếu một lớp có nhiều phụ thuộc và bạn muốn truyền nhiều phụ thuộc thông qua hàm tạo (để chúng không thể thay đổi sau khi bạn khởi tạo đối tượng).

Làm thế nào để bạn thực hiện điều đó mà không cần truyền một mảng phụ thuộc, sử dụng call_user_func_array(), eval() hoặc Reflection? Đây là những gì tôi đang tìm kiếm:

<?php 

class DI 
{ 
    public function getClass($classname) 
    { 
     if(!$this->pool[$classname]) { 
      # Load dependencies 
      $deps = $this->loadDependencies($classname); 

      # Here is where the magic should happen 
      $instance = new $classname($dep1, $dep2, $dep3); 

      # Add to pool 
      $this->pool[$classname] = $instance; 

      return $instance; 
     } else { 
       return $this->pool[$classname]; 
     } 
    } 
} 

Một lần nữa, tôi muốn tránh các phương pháp tốn kém nhất để gọi cho lớp học. Bất cứ một đề nghị nào khác?

Ngoài ra, làm cách nào để truy cập lớp DI bên trong lớp học, ví dụ: trong trình điều khiển cần truy cập các mô hình khác nhau? Tôi có nên gọi nó tĩnh hoặc vượt qua nó theo từng lớp mà sẽ yêu cầu nó? Tôi không nghĩ ý tưởng cuối cùng là khả thi.

Cảm ơn mọi người.

Trả lời

21

[Trước khi bắt đầu, hãy để tôi nói rằng tôi chủ yếu là một lập trình viên Java - chỉ với một chút kiến ​​thức về PHP. Nhưng tôi sẽ chỉ đơn giản là cố gắng để có được những khái niệm quan trọng nhất trên mà không cần chi tiết cụ thể ngôn ngữ]

Dependency Injection dựa trên hai phần mã:.

  1. Xây dựng
  2. Thực hiện

Trong hình dạng cực đoan nhất của nó, không có các toán tử new nào được tìm thấy trong phần Thực thi. Tất cả chúng đều được chuyển vào phần Xây dựng. (Trong thực tế, điều này sẽ được giảm bớt.)

Tất cả việc xây dựng xảy ra - trong phần Xây dựng. Nó tạo ra đồ thị của các đối tượng cần thiết để thực thi dưới lên. Vì vậy, chúng ta hãy giả định, cần xây dựng A:

  • Một phụ thuộc vào B, và
  • B phụ thuộc vào C.

Sau đó

  • C được xây dựng đầu tiên.
  • Sau đó, B được tạo bằng C làm tham số.
  • Sau đó, A được tạo bằng B làm tham số.

Vì vậy, C không phải được chuyển thành tham số hàm tạo cho A. Ví dụ nhỏ này không minh họa đủ mạnh, số lượng đối tượng này phải được chuyển xung quanh khá nhỏ đến mức nào con số.

Chính bản thân bộ phận phụ thuộc không được chuyển vào phần thi hành. Đây là một trong những sai lầm cơ bản mà mọi người (kể cả bản thân tôi) cố gắng thực hiện, khi họ lần đầu tiên tiếp xúc với DI. Vấn đề là, điều này sẽ làm mờ hoàn toàn ranh giới giữa Xây dựng và Thi hành. Một cách khác để nói rằng, nó sẽ vi phạm Law of Demeter. Hoặc trong mô hình nói: Nó cuối cùng sẽ "làm suy thoái" mẫu Dependency Injection thành mẫu Locator Service. Nó gây tranh cãi, nếu điều này thực sự là một sự suy thoái, nhưng trong mọi trường hợp nó thường không phải là một ý tưởng tốt để sử dụng sai Dependency Injector như một Service Locator. Vì vậy, bất cứ khi nào bạn cần cung cấp cho một trong các đối tượng được xây dựng của bạn khả năng tạo ra các đối tượng khác trong quá trình thực thi, thay vì truyền đi Dependency Injector, bạn sẽ chỉ chuyển các Nhà cung cấp đơn giản (một thuật ngữ được sử dụng bởi khung Java DI Guice). Đây là những lớp học khá đơn giản chỉ có thể tạo ra một loại đối tượng nhất định. Họ có điểm tương đồng với một nhà máy.

Trước tiên, hãy cố chuyển các phụ thuộc bắt buộc trực tiếp cho hàm tạo.

Vì vậy, để tóm tắt:

  • xây dựng các đối tượng từ dưới lên.
  • Chỉ chuyển một số phụ thuộc theo yêu cầu để tạo đối tượng.
  • Khi bạn đã hoàn tất, hãy bắt đầu thực hiện.
  • Trong khi thực hiện, bạn vẫn có thể tìm nạp đối tượng mới được tạo bằng cách sử dụng Nhà cung cấp.

Nhưng đừng mang nó quá xa: đối tượng đơn giản vẫn có thể được tạo ra mà không có một nhà cung cấp :-)

Và bây giờ, tất cả các bạn sẽ phải làm là để dịch công cụ này vào mã chất lượng. Có lẽ những người khác có thể giúp bạn với một vài ví dụ PHP.

Phụ lục: hơn một chút về cung cấp

Như đã đề cập ở trên, khái niệm "Nhà cung cấp" (một nhà máy chuyên dùng) là một chút cụ thể cho các khuôn khổ Java DI Guice. Khung công tác này có thể tự động tạo Nhà cung cấp cho bất kỳ loại đối tượng nào. Tuy nhiên, khái niệm này thường hữu ích cho DI. Sự khác biệt duy nhất là, nếu không có sự trợ giúp của Guice hoặc một khuôn khổ tương tự, bạn sẽ phải tự viết Nhà cung cấp - nhưng điều đó khá dễ dàng:

Giả sử, B phụ thuộc vào C.

  • Nếu B chỉ cần một trường hợp cố định của C, sau đó bạn không cần một nhà cung cấp - bạn chỉ có thể xây dựng B với các đối số constructor C.
  • Nếu B cần phải tạo thêm trường hợp của C trong quá trình thực , sau đó chỉ cần viết một lớp được gọi là CProvider với phương thức get(), có thể tạo một phiên bản mới của C. Sau đó, chuyển trường hợp CProvider vào hàm tạo B và lưu trữ Nhà cung cấp trong trường thể hiện B. Bây giờ B có thể gọi cProvider.get() khi cần một phiên bản mới của C.

Nhà cung cấp là một phần của mã Xây dựng, vì vậy bạn được phép sử dụng new C(...)! Mặt khác, chúng không phải là một phần của mã Execution, vì vậy bạn không nên có bất kỳ logic thực thi nào ở đó.

CProvider có thể được chuyển vào nhiều nhà thầu trong khóa học. Bạn cũng có thể viết nhiều phiên bản CProvider1, CProvider2, ... - nơi mỗi người có thể tạo các phiên bản khác nhau của các đối tượng C với các thuộc tính khác nhau. Hoặc bạn khởi tạo đơn giản CProvider nhiều lần với các đối số khác nhau.

+0

Cái nhìn sâu sắc, cảm ơn lời giải thích. Tôi biết về mô hình Dịch vụ định vị và đó không phải là những gì tôi đang cố gắng hoàn thành. Bạn có thể vui lòng xây dựng một chút về việc sử dụng các nhà cung cấp? – Andre

+0

Đã thêm phụ lục. Hãy cho tôi biết nếu bạn cần thêm thông tin. –

+0

Cảm ơn bạn rất nhiều vì đã giúp đỡ. Về cơ bản, tôi cần phải vượt qua các nhà cung cấp được yêu cầu cho mỗi phụ thuộc nhiều phiên bản. Đây là những mẫu cơ bản của Nhà máy nhưng cụ thể để tạo ra các đối tượng cho một mục đích (có thể là một loạt các lớp, một ví dụ sẽ là các trình điều khiển đầu ra) và trả về chúng cho lớp phụ thuộc. Nghe có vẻ phức tạp hơn: D – Andre

2

Bạn nên xem xét sử dụng vùng chứa IOC để quản lý các phụ thuộc của bạn cho bạn. Một thùng chứa IOC tốt nên chăm sóc vượt qua sự phụ thuộc giữa các chất phụ thuộc cho bạn.

Hiện có question hiện có về các tùy chọn vùng chứa IOC cho PHP.

2

Dường như bạn đang cố gắng cuộn vùng chứa tiêm phụ thuộc của riêng mình. Tại sao không sử dụng thiết bị đã tồn tại, như Symfony, Crafty hoặc Sphicy?

+0

Mục tiêu là tránh sử dụng bất kỳ thư viện của bên thứ ba nào trừ khi được yêu cầu hoàn toàn (chủ yếu là do các vấn đề cấp phép). – Andre

+0

@andre: Symfony được cấp phép theo giấy phép MIT. Đọc nó, về cơ bản nói "làm những gì bạn muốn": http://www.opensource.org/licenses/mit-license.php –

+2

Tôi đang tạo giấy phép của riêng mình và không muốn phân bổ cho thư viện của bên thứ ba hoặc phần mềm (một phần của các yêu cầu dự án), như vậy tôi cần phải tạo container riêng của mình. – Andre

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