Có bao nhiêu mũi tiêm được chấp nhận trong một lớp khi sử dụng tiêm phụ thuộc


9

Tôi đang sử dụng Unity trong C # để tiêm phụ thuộc, nhưng câu hỏi nên được áp dụng cho bất kỳ ngôn ngữ và khung nào đang sử dụng nội dung tiêm phụ thuộc.

Tôi đang cố gắng tuân theo nguyên tắc RẮN và do đó tôi có rất nhiều điều trừu tượng. Nhưng bây giờ tôi đang tự hỏi liệu có cách thực hành tốt nhất cho một lớp nên tiêm bao nhiêu lần không?

Ví dụ, tôi có một kho lưu trữ với 9 mũi tiêm. Điều này sẽ khó đọc cho một nhà phát triển khác?

Các mũi tiêm có trách nhiệm sau đây:

  • IDbContextFactory - tạo bối cảnh cho cơ sở dữ liệu.
  • IMapper - Ánh xạ từ các thực thể đến các mô hình miền.
  • IClock - Tóm tắt DateTime. Làm thế nào để giúp kiểm tra đơn vị.
  • IPerformanceFactory - đo thời gian thực hiện cho các phương thức cụ thể.
  • ILog - Log4net để đăng nhập.
  • ICollectionWrapperFactory - Tạo các bộ sưu tập (mở rộng IEnumerable).
  • IQueryFilterFactory - Tạo các truy vấn dựa trên đầu vào sẽ truy vấn db.
  • IIdentityHelper - Truy xuất người dùng đã đăng nhập.
  • IFaultFactory - Tạo FaultExceptions khác nhau (Tôi sử dụng WCF).

Tôi không thực sự thất vọng với cách tôi ủy thác trách nhiệm, nhưng tôi bắt đầu lo lắng về tính dễ đọc.

Vì vậy, câu hỏi của tôi:

Có giới hạn cho việc tiêm bao nhiêu lớp không? Và nếu vậy, làm thế nào để tránh nó?

Có nhiều mũi tiêm giới hạn khả năng đọc, hoặc nó thực sự cải thiện nó?


2
Đo lường chất lượng bằng các con số thường tệ như được trả bằng các dòng mã bạn viết mỗi tháng. Tuy nhiên, bạn đã bao gồm ví dụ thực tế về các phụ thuộc, đó là một ý tưởng tuyệt vời. Nếu tôi là bạn, tôi sẽ điều chỉnh lại câu hỏi của bạn để loại bỏ khái niệm đếm và giới hạn nghiêm ngặt, và để tập trung thay vì chất lượng mỗi lần. Trong khi cải cách nó, hãy cẩn thận để không làm cho câu hỏi của bạn quá cụ thể.
Arseni Mourzenko

3
Có bao nhiêu đối số constructor được chấp nhận? IoC không thay đổi điều đó .
Telastyn

Tại sao mọi người luôn muốn giới hạn tuyệt đối?
Marjan Venema

1
@Telastyn: không nhất thiết Những gì IoC thay đổi là thay vì dựa vào các lớp tĩnh / singletons / biến toàn cục, tất cả các phụ thuộc đều tập trung hơn và có thể nhìn thấy nhiều hơn.
Arseni Mourzenko

@MarjanVenema: bởi vì nó làm cho cuộc sống dễ dàng hơn nhiều. Nếu bạn biết chính xác LỘC tối đa cho mỗi phương thức hoặc số phương thức tối đa trong một lớp hoặc số lượng biến tối đa trên một phương thức và đây là điều duy nhất quan trọng, thì việc xác định mã là tốt hay xấu là điều dễ dàng. cũng như khắc phục lỗi mã lỗi xấu. Điều này thật đáng tiếc rằng cuộc sống thực phức tạp hơn thế nhiều và nhiều số liệu chủ yếu không liên quan.
Arseni Mourzenko

Câu trả lời:


11

Quá nhiều phụ thuộc có thể chỉ ra rằng chính lớp đang làm quá nhiều. Để xác định xem nó có làm quá nhiều không:

  • Nhìn vào lớp học Nó sẽ có ý nghĩa để chia nó thành hai, ba, bốn? Liệu nó có ý nghĩa như một toàn thể?

  • Nhìn vào các loại phụ thuộc. Cái nào là miền cụ thể, và cái nào là toàn cầu Chẳng hạn, tôi sẽ không xem xét ILogở cùng cấp độ như IQueryFilterFactory: lớp đầu tiên sẽ có sẵn trong hầu hết các lớp kinh doanh nếu họ đang sử dụng đăng nhập. Mặt khác, nếu bạn tìm thấy nhiều phụ thuộc theo miền cụ thể, điều này có thể cho thấy rằng lớp đang làm quá nhiều.

  • Nhìn vào các phụ thuộc có thể được thay thế bằng các giá trị.

    IClock - Tóm tắt DateTime. Làm thế nào để giúp kiểm tra đơn vị.

    Điều này có thể dễ dàng được thay thế bằng cách DateTime.Nowchuyển trực tiếp đến các phương thức cần biết thời gian hiện tại.

Bằng cách nhìn vào các phụ thuộc thực tế, tôi không thấy bất cứ điều gì có thể là dấu hiệu của những điều xấu xảy ra:

  • IDbContextFactory - tạo bối cảnh cho cơ sở dữ liệu.

    OK, có lẽ chúng ta đang ở trong một lớp nghiệp vụ nơi các lớp tương tác với lớp truy cập dữ liệu. Nhìn ổn.

  • IMapper - Ánh xạ từ các thực thể đến các mô hình miền.

    Thật khó để nói bất cứ điều gì mà không có bức tranh tổng thể. Có thể kiến ​​trúc đã sai và việc ánh xạ phải được thực hiện trực tiếp bởi lớp truy cập dữ liệu hoặc có thể kiến ​​trúc đó hoàn toàn ổn. Trong mọi trường hợp, nó có ý nghĩa để có sự phụ thuộc này ở đây.

    Một lựa chọn khác là chia lớp thành hai: một xử lý ánh xạ, lớp còn lại xử lý logic nghiệp vụ thực tế. Điều này sẽ tạo ra một lớp thực tế sẽ tách BL ra khỏi DAL. Nếu ánh xạ là phức tạp, nó có thể là một ý tưởng tốt. Trong hầu hết các trường hợp, mặc dù, nó sẽ chỉ thêm sự phức tạp vô dụng.

  • IClock - Tóm tắt DateTime. Làm thế nào để giúp kiểm tra đơn vị.

    Có lẽ không hữu ích lắm khi có một giao diện (và lớp) riêng biệt chỉ để có được thời gian hiện tại. Tôi chỉ đơn giản là sẽ chuyển DateTime.Nowcác phương thức đòi hỏi thời gian hiện tại.

    Một lớp riêng biệt có thể có ý nghĩa nếu có một số thông tin khác, như múi giờ hoặc phạm vi ngày, v.v.

  • IPerformanceFactory - đo thời gian thực hiện cho các phương thức cụ thể.

    Xem điểm tiếp theo.

  • ILog - Log4net để đăng nhập.

    Chức năng siêu việt như vậy phải thuộc về khung và các thư viện thực tế phải có thể thay thế và cấu hình được khi chạy (ví dụ thông qua app.config trong .NET).

    Thật không may, đây không phải là (chưa), cho phép bạn chọn một thư viện và gắn bó với nó, hoặc tạo một lớp trừu tượng để có thể trao đổi các thư viện sau này nếu cần. Nếu ý định của bạn là đặc biệt độc lập với sự lựa chọn của thư viện, hãy thực hiện nó. Nếu bạn khá chắc chắn rằng bạn sẽ tiếp tục sử dụng thư viện trong nhiều năm, đừng thêm một sự trừu tượng.

    Nếu thư viện quá phức tạp để sử dụng, một mẫu mặt tiền có ý nghĩa.

  • ICollectionWrapperFactory - Tạo các bộ sưu tập (mở rộng IEnumerable).

    Tôi giả định rằng điều này tạo ra các cấu trúc dữ liệu rất cụ thể được sử dụng bởi logic miền. Nó trông giống như một lớp tiện ích. Thay vào đó, sử dụng một lớp cho mỗi cấu trúc dữ liệu với các hàm tạo có liên quan. Nếu logic khởi tạo hơi phức tạp để phù hợp với hàm tạo, hãy sử dụng các phương thức tĩnh của nhà máy. Nếu logic thậm chí còn phức tạp hơn, hãy sử dụng nhà máy hoặc mẫu xây dựng.

  • IQueryFilterFactory - Tạo các truy vấn dựa trên đầu vào sẽ truy vấn db.

    Tại sao không phải là trong lớp truy cập dữ liệu? Tại sao có một Filtertrong tên?

  • IIdentityHelper - Truy xuất người dùng đã đăng nhập.

    Tôi không chắc tại sao lại có Helperhậu tố. Trong mọi trường hợp, các hậu tố khác sẽ không đặc biệt rõ ràng ( IIdentityManager?)

    Dù sao, nó có ý nghĩa hoàn hảo để có sự phụ thuộc này ở đây.

  • IFaultFactory - Tạo FaultExceptions khác nhau (Tôi sử dụng WCF).

    Nó logic phức tạp đến mức nó đòi hỏi phải sử dụng một mô hình nhà máy? Tại sao Dependency Injection được sử dụng cho điều đó? Bạn có thể trao đổi việc tạo ra các ngoại lệ giữa mã sản xuất và thử nghiệm không? Tại sao?

    Tôi sẽ cố gắng cấu trúc lại thành đơn giản throw new FaultException(...). Nếu một số thông tin toàn cầu nên được thêm vào tất cả các ngoại lệ trước khi truyền chúng cho khách hàng, WCF có thể có một cơ chế trong đó bạn bắt được một ngoại lệ chưa được xử lý và có thể thay đổi và chia sẻ lại cho khách hàng.

Có giới hạn cho việc tiêm bao nhiêu lớp không? Và nếu vậy, làm thế nào để tránh nó?

Đo lường chất lượng bằng các con số thường tệ như được trả bằng các dòng mã bạn viết mỗi tháng. Bạn có thể có một số lượng lớn các phụ thuộc trong một lớp được thiết kế tốt, vì bạn có thể có một lớp nhảm nhí bằng cách sử dụng một vài phụ thuộc.

Có nhiều mũi tiêm giới hạn khả năng đọc, hoặc nó thực sự cải thiện nó?

Rất nhiều phụ thuộc làm cho logic khó theo dõi hơn. Nếu logic khó theo dõi, lớp có lẽ đang làm quá nhiều và nên được chia.


Cảm ơn bạn đã cho ý kiến ​​và thời gian của bạn. Thay vào đó, chủ yếu là về FaultFactory sẽ được chuyển sang logic WCF. Tôi sẽ giữ IClock vì nó là một trình bảo vệ cuộc sống khi TDD-ing một ứng dụng. Có nhiều lần bạn muốn đảm bảo rằng một giá trị cụ thể đã được đặt với một thời gian nhất định. Sau đó DateTime. Bây giờ không phải lúc nào cũng đủ vì nó không thể nhạo báng.
smoksnes

7

Đây là một ví dụ kinh điển về DI nói với bạn rằng lớp của bạn có thể đang trở nên quá lớn để trở thành một lớp duy nhất. Điều này thường được hiểu là "wow, DI làm cho các nhà xây dựng của tôi lớn hơn jupiter, kỹ thuật này thật kinh khủng", nhưng điều nó THỰC SỰ nói với bạn là "lớp của bạn có một lượng phụ thuộc rất lớn". Biết điều này, chúng ta có thể

  • Thay vào đó, quét vấn đề dưới tấm thảm bằng cách bắt đầu phụ thuộc mới
  • Xem xét lại thiết kế của chúng tôi. Có thể một số phụ thuộc luôn đi cùng nhau và nên được ẩn đằng sau một số trừu tượng khác. Có lẽ lớp của bạn nên được chia thành 2. Có lẽ nó nên được tạo bởi một vài lớp mà mỗi lớp yêu cầu một tập hợp con nhỏ của các phụ thuộc.

Có vô số cách để quản lý các phụ thuộc và không thể nói điều gì hoạt động tốt nhất trong trường hợp của bạn mà không biết mã và ứng dụng của bạn.

Để trả lời câu hỏi cuối cùng của bạn:

  • Có giới hạn trên đối với bao nhiêu phụ thuộc mà một lớp nên có không?

Có, giới hạn trên là "quá nhiều". Có bao nhiêu là quá nhiều"? "Quá nhiều" là khi sự gắn kết của lớp bị "quá thấp". Tất cả phụ thuộc vào. Thông thường nếu phản ứng của bạn với một lớp là "wow, điều này có rất nhiều sự phụ thuộc", thì đó là quá nhiều.

  • Liệu phụ thuộc tiêm cải thiện hoặc làm tổn thương khả năng đọc?

Tôi nghĩ rằng câu hỏi này là sai lệch. Câu trả lời có thể là có hoặc không. Nhưng nó không phải là phần thú vị nhất. Quan điểm của việc tiêm phụ thuộc là làm cho họ THAM GIA. Đó là về việc tạo ra một api không nói dối. Đó là về việc ngăn chặn nhà nước toàn cầu. Đó là về việc làm cho mã có thể kiểm tra được. Đó là về việc giảm khớp nối.

Các lớp được thiết kế tốt với các phương thức được thiết kế hợp lý và được đặt tên dễ đọc hơn các lớp được thiết kế xấu. DI không thực sự cải thiện cũng như không ảnh hưởng đến khả năng đọc mỗi lần, nó chỉ làm cho các lựa chọn thiết kế của bạn nổi bật, và nếu chúng xấu, nó sẽ làm cay mắt bạn. Điều này không có nghĩa là DI làm cho mã của bạn ít đọc hơn, nó chỉ cho bạn thấy rằng mã của bạn đã là một mớ hỗn độn, bạn vừa ẩn nó.


1
Phản hồi tốt. Cảm ơn bạn. Có, giới hạn trên là "quá nhiều". - Tuyệt vời, và rất đúng.
smoksnes

3

Theo Steve McConnel, tác giả của "Hoàn thành mã" có mặt khắp nơi, quy tắc ngón tay cái là hơn 7 là mùi mã gây tổn hại đến khả năng bảo trì. Cá nhân tôi nghĩ rằng con số này thấp hơn trong hầu hết các trường hợp, nhưng thực hiện DI đúng cách sẽ dẫn đến việc có nhiều phụ thuộc để tiêm khi bạn ở rất gần với Root Root. Điều này là bình thường và dự kiến. Đó là một trong những lý do mà các container IoC là một thứ hữu ích và xứng đáng với sự phức tạp mà chúng thêm vào một dự án.

Vì vậy, nếu bạn rất gần với điểm vào của chương trình, điều này là bình thường và có thể chấp nhận được. Nếu bạn tìm hiểu sâu hơn về logic của chương trình, đó có thể là một mùi cần được xử lý.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.