2008-10-29 43 views
15

Giả sử tôi có một lớp gọi là PermissionManager chỉ nên tồn tại một lần cho hệ thống của tôi và về cơ bản hoàn thành chức năng quản lý các quyền khác nhau cho các hành động khác nhau trong ứng dụng của tôi. Bây giờ tôi có một số lớp trong ứng dụng của tôi mà cần để có thể kiểm tra một sự cho phép nhất định trong một trong các phương pháp của nó. Phương thức khởi tạo của lớp này hiện công khai, tức là được người dùng API sử dụng.Thực hành Singleton & Dependency Injection question

Cho đến một vài tuần trước, tôi sẽ phải chỉ đơn giản là có lớp học của tôi gọi sau pseudo-code ở đâu đó:

 PermissionManager.getInstance().isReadPermissionEnabled(this) 

Nhưng kể từ khi tôi đã nhận thấy tất cả mọi người ở đây ghét độc thân + này loại khớp nối, tôi đã tự hỏi giải pháp tốt hơn sẽ là gì, vì các đối số tôi đã đọc đối với các singletons dường như có ý nghĩa (không thể kiểm tra, ghép nối cao, v.v.).

Vì vậy, tôi có thực sự yêu cầu người dùng API chuyển vào một cá thể PermissionManager trong hàm tạo của lớp không? Mặc dù tôi chỉ muốn một cá thể PermissionManager duy nhất tồn tại cho ứng dụng của tôi?

Hoặc tôi đang đi về điều này tất cả sai và nên có một nhà xây dựng ngoài công lập và một nhà máy ở đâu đó mà đi trong trường hợp của PermissionManager cho tôi?


bổ sung thông tin Lưu ý rằng khi tôi nói "Dependency Injection", tôi đang nói về DI Pattern ... Tôi không sử dụng bất kỳ khuôn khổ DI như Guice hoặc mùa xuân. (... chưa)

Trả lời

3

Nếu bạn đang sử dụng khung tiêm phụ thuộc, thì cách phổ biến để xử lý việc này là chuyển một đối tượng PermissionsManager trong hàm dựng hoặc để có thuộc tính của loại PermissionsManager mà khung công tác đặt cho bạn.

Nếu điều này là không khả thi, sau đó yêu cầu người dùng nhận được một thể hiện của lớp này thông qua nhà máy là một lựa chọn tốt. Trong trường hợp này, nhà máy chuyển PermissionManager vào hàm khởi tạo khi nó tạo lớp. Trong ứng dụng của bạn khởi động, bạn sẽ tạo PermissionManager đơn đầu tiên, sau đó tạo nhà máy của bạn, đi qua trong PermissionManager.

Bạn chính xác là thường khó sử dụng cho các khách hàng của một lớp để biết nơi tìm đúng trường hợp PermissionManager và chuyển nó vào (hoặc thậm chí quan tâm đến thực tế là lớp của bạn sử dụng PermissionManager).

Một giải pháp thỏa hiệp mà tôi đã thấy là cung cấp cho lớp của bạn một thuộc tính của loại PermissionManager. Nếu thuộc tính đã được thiết lập (ví dụ, trong một bài kiểm tra đơn vị), bạn sử dụng cá thể đó, nếu không bạn sử dụng singleton. Một cái gì đó như:

PermissionManager mManager = null; 
public PermissionManager Permissions 
{ 
    if (mManager == null) 
    { 
    return mManager; 
    } 
    return PermissionManager.getInstance(); 
} 

Tất nhiên, nói đúng, PermissionManager bạn nên thực hiện một số loại giao diện IPermissionManager, và đó là gì lớp khác bạn nên tham khảo do đó, một thi giả có thể được thay thế dễ dàng hơn trong quá trình thử nghiệm.

+1

Điểm về việc tiêm thông qua giao diện là một điểm quan trọng. Khả năng giả lập đối tượng PermissionManager trong các thử nghiệm là điều làm cho DI trở thành một cách tiếp cận mạnh mẽ để có thể kiểm tra được mã. –

+1

nếu PermissionManager chính nó có một phụ thuộc. Có cách nào ít lạ hơn PermissionManager.getInstance (Foo) không? ? –

0

Mẫu đơn không phải là xấu, mà làm cho nó xấu xí là cách nó thường được sử dụng, như là yêu cầu chỉ muốn một trường hợp duy nhất của một lớp nhất định, mà tôi nghĩ đó là sai lầm lớn.

Trong trường hợp này, tôi muốn PermissionManager là một lớp tĩnh trừ khi vì bất kỳ lý do gì bạn cần nó là một loại instanciable.

2

Bạn thực sự có thể bắt đầu bằng cách tiêm PermissionManager. Điều này sẽ làm cho lớp của bạn dễ kiểm tra hơn.

Nếu điều này gây ra sự cố cho người dùng của lớp đó, bạn có thể yêu cầu họ sử dụng phương pháp nhà máy hoặc nhà máy trừu tượng. Hoặc bạn có thể thêm một constructor không có tham số để họ gọi rằng inject PermissionManager trong khi các test của bạn sử dụng một hàm tạo khác mà bạn có thể sử dụng để giả lập PermissionManager.

Việc tách lớp học của bạn nhiều hơn khiến các lớp học của bạn trở nên linh hoạt hơn nhưng nó cũng có thể khiến chúng khó sử dụng hơn. Nó phụ thuộc vào tình hình những gì bạn sẽ cần. Nếu bạn chỉ có một PermissionManager và không có vấn đề kiểm tra các lớp học sử dụng nó thì không có lý do gì để sử dụng DI. Nếu bạn muốn mọi người có thể thêm thực thi PermissionManager của riêng họ thì DI là con đường để đi.

2

Nếu bạn đang đăng ký cách tiêm phụ thuộc vào việc làm mọi thứ, bất kỳ lớp nào cần PermissionManager của bạn nên có nó được tiêm dưới dạng đối tượng đối tượng. Cơ chế kiểm soát sự khởi tạo của nó (để thực thi bản chất đơn) hoạt động ở mức cao hơn. Nếu bạn sử dụng một khuôn khổ tiêm phụ thuộc như Guice, nó có thể thực hiện công việc thực thi. Nếu bạn đang làm đối tượng dây của bạn bằng tay, tiêm phụ thuộc ủng hộ nhóm mã mà không instantiation (mới nhà điều hành công việc) ra khỏi logic kinh doanh của bạn.

Dù bằng cách nào, Singleton cổ điển "vốn-S" thường được xem là dạng chống mẫu trong ngữ cảnh tiêm phụ thuộc.

Những bài đăng đã được sâu sắc cho tôi trong quá khứ:

1

Vì vậy, tôi nên thực sự yêu cầu người dùng API để vượt qua trong một trường hợp PermissionManager trong constructor của lớp học? Mặc dù tôi chỉ muốn một cá thể PermissionManager duy nhất tồn tại cho ứng dụng của tôi?

Vâng, đây là tất cả những gì bạn cần làm. Cho dù phụ thuộc là singleton/per request/per thread hay phương thức factory là trách nhiệm của container và cấu hình của bạn. Trong thế giới .net, chúng ta lý tưởng sẽ có sự phụ thuộc vào một giao diện IPermissionsManager để giảm thêm sự liên kết, tôi cho rằng đây là cách thực hành tốt nhất trong Java.

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