2011-12-21 35 views
9

Tôi không phải là một hater của singletons, nhưng tôi biết họ bị lạm dụng và vì lý do đó tôi muốn tìm hiểu để tránh sử dụng chúng khi không cần thiết.Cần trợ giúp tránh việc sử dụng Singleton

Tôi đang phát triển ứng dụng là nền tảng chéo (Windows XP/Vista/7, Windows Mobile 6.x, Windows CE5, Windows CE6). Là một phần của quy trình, tôi sẽ tính lại mã vào các dự án riêng biệt, để giảm trùng lắp mã, và do đó có cơ hội sửa lỗi của hệ thống sinh dục.

Một phần như vậy của ứng dụng đang được tạo riêng biệt khá đơn giản, đó là trình quản lý hồ sơ. Dự án này chịu trách nhiệm lưu trữ Hồ sơ. Nó có một lớp Profile chứa một số dữ liệu cấu hình được sử dụng bởi tất cả các phần của ứng dụng. Nó có một lớp học ProfileManager có chứa Profiles. ProfileManager sẽ đọc/lưu Profiles dưới dạng tệp XML riêng biệt trên đĩa cứng và cho phép ứng dụng truy xuất và đặt "hoạt động" Profile. Đơn giản.

Trong lần xây dựng bên trong đầu tiên, GUI là SmartGUI chống mẫu. Đó là một thực hiện WinForms mà không MVC/MVP thực hiện bởi vì chúng tôi muốn nó hoạt động sớm hơn là được thiết kế tốt. Điều này dẫn đến ProfileManager là một singleton. Điều này là như vậy từ bất cứ nơi nào trong ứng dụng, GUI có thể truy cập vào hoạt động Profile.

Điều này có nghĩa là tôi chỉ có thể đi ProfileManager.Instance.ActiveProfile để truy xuất cấu hình cho các phần khác nhau của hệ thống nếu cần. Mỗi GUI cũng có thể thay đổi cấu hình, vì vậy mỗi GUI có một nút lưu, vì vậy tất cả chúng đều có quyền truy cập vào phương thức ProfileManager.Instance.SaveActiveProfile().

Tôi thấy không có gì sai trong việc sử dụng singleton ở đây, và bởi vì tôi thấy không có gì sai trong nó nhưng biết singletons không phải là lý tưởng. Có cách nào tốt hơn nên xử lý không? Một cá thể của ProfileManager có được chuyển vào mọi Controller/Presenter không? Khi ProfileManager được tạo, các thành phần cốt lõi khác sẽ được tạo và đăng ký các sự kiện khi các cấu hình được thay đổi. Ví dụ này khá đơn giản, và có lẽ là một tính năng phổ biến trong nhiều hệ thống, vì vậy nghĩ rằng đây là một nơi tuyệt vời để học cách tránh những người độc thân.

P.s. Tôi đang phải xây dựng ứng dụng với Compact Framework 3.5, điều này không giới hạn rất nhiều các lớp .Net Framework thông thường có thể được sử dụng.

+6

Tôi chỉ có thể bị mắc kẹt trong thói quen cũ của mình, nhưng tôi thấy đây là một ví dụ điển hình về việc nên sử dụng Singleton ở đâu. –

+0

Điều này thực sự âm thanh như trường hợp lý tưởng cho một trường hợp singleton. – msarchet

+0

Cảm ơn tất cả các câu trả lời, nó xuất hiện đây là một nơi thích hợp để sử dụng Singleton. Phản hồi về nhà máy/phụ thuộc tiêm sẽ được đưa vào tài khoản, tuy nhiên như ứng dụng này sẽ chạy trong nền tôi sẽ có khả năng để nó như là một Singleton cho cả đơn giản và hiệu suất. – JonWillis

Trả lời

8

Một trong những lý do khiến những người độc thân bị coi là độc hại là họ thường đóng vai trò là vùng chứa cho trạng thái toàn cầu, được chia sẻ và đôi khi có thể thay đổi. Singletons là một trừu tượng tuyệt vời khi ứng dụng của bạn thực sự cần truy cập vào trạng thái chia sẻ toàn cục: ứng dụng di động của bạn cần truy cập micrô hoặc phát lại âm thanh cần điều phối điều này, chẳng hạn như chỉ có một bộ loa.

Trong trường hợp đơn đăng ký của bạn, bạn có một hồ sơ "hoạt động" duy nhất, các phần khác nhau của ứng dụng cần có khả năng sửa đổi. Tôi nghĩ bạn cần phải quyết định xem hồ sơ của người dùng có thực sự phù hợp với sự trừu tượng này hay không. Cho rằng biểu hiện của một hồ sơ là một tập tin XML duy nhất trên đĩa, tôi nghĩ rằng đó là tốt để có như là một singleton.

Tôi nghĩ bạn nên sử dụng tính năng tiêm phụ thuộc hoặc mẫu nhà máy để giữ một người quản lý hồ sơ. Bạn chỉ cần viết một bài kiểm tra đơn vị cho một lớp đòi hỏi việc sử dụng một hồ sơ để hiểu được nhu cầu về điều này; bạn muốn có thể truyền vào một hồ sơ được tạo lập trình trong thời gian chạy, nếu không mã của bạn sẽ có sự phụ thuộc chặt chẽ với một số tệp XML trên đĩa ở đâu đó.

+0

Việc viết lại một phần sẽ được kiểm tra đơn vị, không phải là điểm mạnh của tôi nhưng tôi sẽ cố gắng, vẫn học TDD. Chưa được thử nghiệm, nhưng tôi đoán vấn đề là với chúng là Instance (phương thức hoặc thuộc tính) là tĩnh nên không thể dễ dàng bị giả mạo/stubbed như static không thể bị ghi đè, đó là cách mocks hoạt động (thêm vào một test tạo ra lớp con của lớp đang được chế nhạo). – JonWillis

2

"Singletons" thực sự chỉ tệ nếu chúng chủ yếu được sử dụng để thay thế biến "toàn cục". Trong trường hợp này, và nếu đó là những gì nó đang được sử dụng cho, nó không nhất thiết Singleton anyway.

Trong trường hợp bạn mô tả, điều đó là tốt, và thực tế lý tưởng để ứng dụng của bạn có thể đảm bảo rằng Trình quản lý hồ sơ khả dụng cho mọi người cần nó và không có phần nào khác của ứng dụng có thể tạo thêm sẽ xung đột với hiện tại. Điều này cũng làm giảm các tham số/trường thừa ở khắp mọi nơi, nơi bạn đang cố gắng truyền xung quanh một cá thể, và sau đó duy trì các tham chiếu không cần thiết bổ sung cho nó. Miễn là nó bị buộc vào một và chỉ có một instantiation, tôi thấy không có gì sai với nó.

Singleton được thiết kế để tránh nhiều cảnh báo và điểm duy nhất của "mục nhập". Nếu đó là những gì bạn muốn, thì đó là con đường để đi. Chỉ cần chắc chắn rằng nó cũng tài liệu.

+0

Cảm ơn bạn đã nhập, mối quan tâm của tôi không có "Singleton" và chỉ là "Tham chiếu đơn", là trạng thái của bạn, có các tham số bổ sung trong nhiều phương thức. Mà cuối cùng trở thành một doanh nghiệp lộn xộn. – JonWillis

5

Một điều cần xem xét là có giao diện cho Trình quản lý hồ sơ của bạn và chuyển một thể hiện của nó tới hàm tạo của mỗi chế độ xem (hoặc bất kỳ thứ gì) sử dụng nó. Bằng cách này, bạn có thể dễ dàng có một singleton, hoặc một thể hiện cho mỗi chủ đề/người dùng/etc, hoặc có một thực hiện mà đi đến một cơ sở dữ liệu/dịch vụ web/vv

Một tùy chọn khác sẽ là có tất cả những thứ sử dụng Trình quản lý hồ sơ gọi cho một nhà máy thay vì truy cập trực tiếp vào nó. Sau đó, nhà máy đó có thể trả về một thể hiện, một lần nữa nó có thể là một singleton hay không (đi đến cơ sở dữ liệu hoặc tập tin hoặc dịch vụ web, vv) và hầu hết mã của bạn không cần phải biết.

Không trả lời câu hỏi trực tiếp của bạn, nhưng nó sẽ ảnh hưởng đến thay đổi trong tương lai gần bằng không.

+0

Tôi đã xem xét một giao diện, nhưng biết rằng sẽ chỉ có một loại ProfileManager để quyết định chống lại nó. Sử dụng phương pháp Factory được xem xét khác, nhưng tôi ngần ngại đề xuất nó vì tôi cảm thấy như tôi đang thêm vào mã mà chỉ trả về một singleton, nhưng tôi hiểu nếu triển khai thay đổi, sau đó tôi chỉ cập nhật một tài liệu tham khảo của nhà máy thay vì mỗi phần mã sử dụng singleton đó. Chúc mừng – JonWillis

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