Về mẫu thiết kế: Khi nào tôi nên sử dụng singleton?


448

Biến toàn cầu được tôn vinh - trở thành một lớp toàn cầu được tôn vinh. Một số người nói phá vỡ thiết kế hướng đối tượng.

Cung cấp cho tôi các kịch bản, ngoài logger cũ tốt, nơi sử dụng singleton có ý nghĩa.


4
Kể từ khi học erlang, tôi thích cách tiếp cận đó, cụ thể là tính bất biến và thông điệp truyền qua.
Setori

209
Điều gì không mang tính xây dựng về câu hỏi này? Tôi thấy câu trả lời mang tính xây dựng dưới đây.
mk12

3
Khung tiêm phụ thuộc là một đơn vị rất phức tạp đưa ra đối tượng.
Ian Ringrose

1
Singleton có thể được sử dụng như một đối tượng quản lý giữa các thể hiện của các đối tượng khác, do đó chỉ nên có một thể hiện của singleton trong đó các thể hiện khác nên giao tiếp thông qua thể hiện singleton.
Levent Divilioglu 7/12/2015

Tôi có một câu hỏi phụ: bất kỳ triển khai Singleton nào cũng có thể được thực hiện bằng cách sử dụng lớp "tĩnh" (với phương thức "nhà máy" / "init") - mà không thực sự tạo một thể hiện của một lớp (bạn có thể nói rằng một lớp tĩnh là loại thực hiện Singleton, nhưng ...) - tại sao người ta nên sử dụng một Singleton thực tế (một thể hiện một lớp duy nhất để đảm bảo duy nhất của nó) thay vì một lớp tĩnh? Lý do duy nhất tôi có thể nghĩ đến có lẽ là vì "ngữ nghĩa", nhưng ngay cả trong ý nghĩa đó, các trường hợp sử dụng Singleton không thực sự đòi hỏi mối quan hệ "lớp-> thể hiện" theo định nghĩa ... vậy ... tại sao?
Yuval A.

Câu trả lời:


358

Trong hành trình tìm kiếm sự thật, tôi phát hiện ra rằng thực sự có rất ít lý do "chấp nhận được" để sử dụng Singleton.

Một lý do có xu hướng xuất hiện lặp đi lặp lại trên mạng quốc tế là vì lớp "ghi nhật ký" (mà bạn đã đề cập). Trong trường hợp này, một Singleton có thể được sử dụng thay vì một thể hiện của một lớp vì một lớp ghi nhật ký thường cần được sử dụng lặp đi lặp lại nhiều lần bởi mỗi lớp trong một dự án. Nếu mỗi lớp sử dụng lớp ghi nhật ký này, việc tiêm phụ thuộc sẽ trở nên cồng kềnh.

Ghi nhật ký là một ví dụ cụ thể của Singleton "chấp nhận được" vì nó không ảnh hưởng đến việc thực thi mã của bạn. Vô hiệu hóa đăng nhập, thực thi mã vẫn như cũ. Cho phép nó, giống nhau. Misko đưa nó theo cách sau trong Root Nguyên nhân của Singletons , "Thông tin ở đây chảy theo một cách: Từ ứng dụng của bạn vào logger. Mặc dù logger là trạng thái toàn cầu, vì không có thông tin nào chuyển từ logger vào ứng dụng của bạn, logger có thể chấp nhận được."

Tôi chắc chắn có những lý do hợp lệ khác là tốt. Alex Miller, trong " Mẫu tôi ghét ", nói về người định vị dịch vụ và giao diện người dùng phía khách hàng cũng có thể là những lựa chọn "có thể chấp nhận".

Đọc thêm tại Singleton Tôi yêu bạn, nhưng bạn đang làm tôi thất vọng.


3
@ArneMertz Tôi đoán đây là một.
Tấn công

1
Tại sao bạn không thể sử dụng một đối tượng toàn cầu? Tại sao nó phải là một singleton?
Giày

1
Tôi nghĩ phương pháp tĩnh cho một sử dụng đăng nhập?
Skynet

1
Singletons là tốt nhất khi bạn cần quản lý tài nguyên. Ví dụ: kết nối http. Bạn không muốn thiết lập 1 triệu khách hàng http cho một khách hàng, điều đó thật lãng phí và chậm chạp. Vì vậy, một singleton với một máy khách http kết nối sẽ nhanh hơn và thân thiện với tài nguyên hơn nhiều.
Cogman

3
Tôi biết đây là một câu hỏi cũ, và thông tin trong câu trả lời này là tuyệt vời. Tuy nhiên, tôi gặp khó khăn trong việc hiểu tại sao đây là câu trả lời được chấp nhận khi OP chỉ định rõ ràng: "Hãy đưa cho tôi các kịch bản, ngoài trình ghi nhật ký cũ tốt, nơi sử dụng singleton có ý nghĩa."
Francisco C.

124

Một ứng cử viên Singleton phải đáp ứng ba yêu cầu:

  • kiểm soát truy cập đồng thời vào một tài nguyên được chia sẻ.
  • truy cập vào tài nguyên sẽ được yêu cầu từ nhiều phần khác nhau của hệ thống.
  • chỉ có thể có một đối tượng

Nếu Singleton đề xuất của bạn chỉ có một hoặc hai trong số các yêu cầu này, thiết kế lại gần như luôn luôn là lựa chọn chính xác.

Ví dụ, bộ đệm máy in không có khả năng được gọi từ nhiều nơi (menu In), vì vậy bạn có thể sử dụng mutexes để giải quyết vấn đề truy cập đồng thời.

Một logger đơn giản là ví dụ rõ ràng nhất về Singleton có thể hợp lệ, nhưng điều này có thể thay đổi với các sơ đồ ghi nhật ký phức tạp hơn.


3
Tôi không đồng ý với điểm 2. Điểm 3 không thực sự là một lý do (chỉ vì bạn có thể không có nghĩa là bạn nên) và 1 là một điểm tốt nhưng tôi vẫn không thấy sử dụng nó. Giả sử tài nguyên được chia sẻ là ổ đĩa hoặc bộ đệm db. Bạn có thể thêm một ổ đĩa khác hoặc có bộ đệm db tập trung vào một thứ khác (chẳng hạn như bộ đệm cho một bảng chuyên dụng cho một luồng với mục đích khác là mục đích chung hơn).

15
Tôi nghĩ bạn đã bỏ lỡ từ "ứng cử viên". Một ứng cử viên Singleton phải đáp ứng ba yêu cầu; chỉ vì một cái gì đó đáp ứng các yêu cầu, không có nghĩa nó phải là một Singleton. Có thể có các yếu tố thiết kế khác :)
metao

45

Đọc các tệp cấu hình chỉ nên đọc khi khởi động và gói chúng trong Singleton.


8
Tương tự như Properties.Settings.Defaulttrong .NET.
Nick Bedford

9
@Paul, "trại không độc thân" sẽ nói rằng đối tượng cấu hình đơn giản nên được chuyển vào các chức năng cần nó, thay vì làm cho nó có thể truy cập toàn cầu (hay còn gọi là singleton).
Pacerier

2
Không đồng ý. Nếu cấu hình được chuyển đến cơ sở dữ liệu, mọi thứ đều bị sai lệch. Nếu đường dẫn đến cấu hình phụ thuộc vào bất cứ thứ gì bên ngoài singleton, những thứ này cũng cần phải tĩnh.
rr-

3
@PaulCroarkin Bạn có thể mở rộng về điều này và giải thích điều này có lợi như thế nào không?
AlexG

1
@ rr- nếu cấu hình di chuyển đến cơ sở dữ liệu, nó vẫn có thể được gói gọn trong một đối tượng cấu hình sẽ được chuyển vào các hàm cần nó. (PS Tôi không ở trong trại "không độc thân").
Will Sheppard

36

Bạn sử dụng một singleton khi bạn cần quản lý tài nguyên được chia sẻ. Ví dụ, một bộ đệm máy in. Ứng dụng của bạn chỉ nên có một phiên bản duy nhất của bộ đệm để tránh yêu cầu xung đột cho cùng một tài nguyên.

Hoặc kết nối cơ sở dữ liệu hoặc trình quản lý tệp, v.v.


30
Tôi đã nghe ví dụ về bộ đệm máy in này và tôi nghĩ nó hơi khập khiễng. Ai nói tôi không thể có nhiều hơn một bộ đệm? Cái quái gì là một bộ đệm máy in? Điều gì xảy ra nếu tôi có các loại máy in khác nhau không thể xung đột hoặc sử dụng các trình điều khiển khác nhau?
1800 THÔNG TIN

6
Đây chỉ là một ví dụ ... cho bất kỳ tình huống nào mà bất kỳ ai sử dụng làm ví dụ, bạn sẽ có thể tìm thấy một thiết kế thay thế làm cho ví dụ trở nên vô dụng. Hãy giả vờ rằng bộ đệm quản lý một tài nguyên được chia sẻ bởi nhiều thành phần. Nó hoạt động.
Vincent Ramdhanie

2
Đó là ví dụ kinh điển cho Gang of Four. Tôi nghĩ rằng một câu trả lời với một trường hợp sử dụng thử thực sự sẽ hữu ích hơn. Ý tôi là một tình huống mà bạn thực sự cảm thấy Singleton là giải pháp tốt nhất.
Andrei Vajna II

Một tài nguyên được chia sẻ là trong ví dụ của tôi một ví dụ quá rộng. Làm thế nào bạn có thể kiểm tra các đối tượng sử dụng bộ đệm in đang hoạt động chính xác khi đối mặt với bộ đệm bị hỏng khi bạn không thể thực hiện việc triển khai 'bộ đệm' bị trục trặc? mặc dù ngắn và không chính xác, câu trả lời được chấp nhận là một cách tiếp cận an toàn hơn rất nhiều trong cuốn sách của tôi
Rune FS

Cái gì là một bộ đệm máy in?
RayLovless

23

Chỉ đọc các singletons lưu trữ một số trạng thái toàn cầu (ngôn ngữ người dùng, filepath trợ giúp, đường dẫn ứng dụng) là hợp lý. Hãy cẩn thận khi sử dụng singletons để kiểm soát logic kinh doanh - đơn lẻ hầu như luôn luôn là nhiều


4
Ngôn ngữ người dùng chỉ có thể là singleton với giả định rằng chỉ một người dùng có thể sử dụng hệ thống.
Samuel Åslund

Chỉ và một người dùng chỉ nói một ngôn ngữ.
quang phổ

17

Quản lý kết nối (hoặc nhóm kết nối) với cơ sở dữ liệu.

Tôi cũng sẽ sử dụng nó để lấy và lưu trữ thông tin trên các tập tin cấu hình bên ngoài.


2
Sẽ không một trình tạo kết nối cơ sở dữ liệu là một ví dụ về Nhà máy?
Ken

3
@Ken bạn muốn nhà máy đó là một singleton trong hầu hết các trường hợp.
Chris Marisic

2
@Federico, "trại không độc thân" sẽ nói rằng (các) kết nối cơ sở dữ liệu này đơn giản nên được chuyển vào các chức năng cần chúng, thay vì làm cho chúng có thể truy cập toàn cầu (hay còn gọi là singleton).
Pacerier

3
Bạn không thực sự cần một singleton cho việc này. Nó có thể được tiêm.
Nestor Ledon

11

Một trong những cách bạn sử dụng một singleton là bao gồm một trường hợp trong đó phải có một "nhà môi giới" duy nhất kiểm soát quyền truy cập vào tài nguyên. Singletons là tốt trong logger bởi vì họ môi giới truy cập vào, nói, một tập tin, chỉ có thể được viết riêng. Đối với một cái gì đó như đăng nhập, họ cung cấp một cách trừu tượng hóa việc ghi vào một cái gì đó giống như một tệp nhật ký - bạn có thể gói một cơ chế bộ đệm vào đĩa đơn của mình, v.v ...

Cũng nghĩ về một tình huống mà bạn có một ứng dụng có nhiều cửa sổ / luồng / vv, nhưng cần một điểm giao tiếp duy nhất. Tôi đã từng sử dụng một để kiểm soát các công việc mà tôi muốn ứng dụng của mình khởi chạy. Người độc thân chịu trách nhiệm tuần tự hóa các công việc và hiển thị trạng thái của họ cho bất kỳ phần nào khác của chương trình mà họ quan tâm. Trong loại kịch bản này, bạn có thể xem một singleton giống như một lớp "máy chủ" đang chạy bên trong ứng dụng của bạn ... HTH


3
Các logger thường là Singletons để các đối tượng đăng nhập không phải truyền qua. Bất kỳ triển khai tốt nào của một luồng nhật ký sẽ đảm bảo rằng việc ghi đồng thời là không thể, cho dù đó là Singleton hay không.
metao

10

Một singleton nên được sử dụng khi quản lý quyền truy cập vào một tài nguyên được chia sẻ bởi toàn bộ ứng dụng và nó sẽ bị phá hủy khi có nhiều phiên bản của cùng một lớp. Đảm bảo rằng quyền truy cập vào luồng tài nguyên được chia sẻ an toàn là một ví dụ rất hay về việc loại mẫu này có thể là quan trọng.

Khi sử dụng Singletons, bạn nên đảm bảo rằng bạn không vô tình che giấu sự phụ thuộc. Lý tưởng nhất là các singletons (giống như hầu hết các biến tĩnh trong ứng dụng) được thiết lập trong quá trình thực thi mã khởi tạo của bạn cho ứng dụng (static void Main () cho các tệp thực thi C #, static void main () cho các tệp thực thi java) và sau đó được truyền vào tất cả các lớp khác được khởi tạo mà yêu cầu nó. Điều này giúp bạn duy trì khả năng kiểm tra.


8

Tôi nghĩ rằng việc sử dụng singleton có thể được coi là giống như mối quan hệ nhiều-một trong cơ sở dữ liệu. Nếu bạn có nhiều phần khác nhau của mã cần làm việc với một thể hiện của một đối tượng, thì đó là nơi hợp lý khi sử dụng singletons.


6

Một ví dụ thực tế về một singleton có thể được tìm thấy trong Test :: Builder , lớp chỉ hỗ trợ cho mọi mô-đun thử nghiệm Perl hiện đại. Test :: Builder singleton lưu trữ và môi giới trạng thái và lịch sử của quá trình thử nghiệm (kết quả thử nghiệm lịch sử, đếm số lần chạy thử) cũng như những thứ như nơi đầu ra thử nghiệm đang diễn ra. Đây là tất cả cần thiết để phối hợp nhiều mô-đun thử nghiệm, được viết bởi các tác giả khác nhau, để làm việc cùng nhau trong một kịch bản thử nghiệm duy nhất.

Lịch sử của Test :: Singleton là giáo dục. Gọi new()luôn cho bạn cùng một đối tượng. Đầu tiên, tất cả dữ liệu được lưu trữ dưới dạng các biến lớp không có gì trong chính đối tượng. Điều này hoạt động cho đến khi tôi muốn kiểm tra Test :: Builder với chính nó. Sau đó, tôi cần hai đối tượng Test :: Builder, một thiết lập như một hình nộm, để nắm bắt và kiểm tra hành vi và đầu ra của nó, và một đối tượng là đối tượng thử nghiệm thực sự. Tại thời điểm đó, Test :: Builder được tái cấu trúc thành một đối tượng thực sự. Đối tượng singleton được lưu trữ dưới dạng dữ liệu lớp và new()sẽ luôn trả về nó. create()đã được thêm vào để tạo một đối tượng mới và cho phép thử nghiệm.

Hiện tại, người dùng đang muốn thay đổi một số hành vi của Test :: Builder trong mô-đun của riêng họ, nhưng để những người khác ở một mình, trong khi lịch sử thử nghiệm vẫn phổ biến trên tất cả các mô-đun thử nghiệm. Điều đang xảy ra bây giờ là đối tượng Test :: Monolithic nguyên khối đang được chia thành các phần nhỏ hơn (lịch sử, đầu ra, định dạng ...) với một đối tượng Test :: Builder thu thập chúng lại với nhau. Bây giờ Test :: Builder không còn phải là một singleton. Các thành phần của nó, giống như lịch sử, có thể. Điều này đẩy sự cần thiết không thể thay đổi của một người độc thân xuống một cấp độ. Nó mang lại sự linh hoạt hơn cho người dùng đối với các mảnh ghép và kết hợp. Các đối tượng singleton nhỏ hơn bây giờ có thể chỉ lưu trữ dữ liệu, với các đối tượng chứa chúng quyết định cách sử dụng nó. Nó thậm chí còn cho phép một lớp Non-Test :: Builder chơi cùng bằng cách sử dụng lịch sử Test :: Builder và singletons đầu ra.

Dường như có sự thúc đẩy giữa việc phối hợp dữ liệu và tính linh hoạt của hành vi có thể được giảm thiểu bằng cách đặt đơn lẻ xung quanh dữ liệu được chia sẻ với lượng hành vi nhỏ nhất có thể để đảm bảo tính toàn vẹn của dữ liệu.


5

Khi bạn tải một đối tượng Thuộc tính cấu hình, từ cơ sở dữ liệu hoặc tệp, sẽ giúp nó có dạng đơn lẻ; không có lý do để tiếp tục đọc lại dữ liệu tĩnh sẽ không thay đổi trong khi máy chủ đang chạy.


2
Tại sao bạn không chỉ tải dữ liệu một lần và truyền đối tượng cấu hình khi cần?
lagweezle

những gì đang đi qua xung quanh ??? Nếu tôi phải vượt qua mọi đối tượng tôi cần, tôi sẽ có các nhà xây dựng với 20 đối số ...
Enerccio

@Enerccio Nếu bạn có các đối tượng dựa trên 20 đối tượng khác mà không đóng gói, bạn đã có vấn đề thiết kế lớn.
quang phổ

@spectras Tôi có làm không? Nếu tôi thực hiện hộp thoại gui, tôi sẽ cần: kho lưu trữ, bản địa hóa, dữ liệu phiên, dữ liệu ứng dụng, phụ huynh, dữ liệu khách hàng, trình quản lý cấp phép và có thể nhiều hơn nữa. Chắc chắn, bạn có thể tổng hợp một số, nhưng tại sao? Cá nhân tôi sử dụng mùa xuân và các khía cạnh để chỉ tự động tất cả các phụ thuộc này vào lớp widget và điều đó tách rời mọi thứ.
Enerccio

Nếu bạn có nhiều trạng thái đó, bạn có thể xem xét triển khai mặt tiền, đưa ra quan điểm về các khía cạnh liên quan đến bối cảnh cụ thể. Tại sao? Bởi vì nó sẽ cho phép một thiết kế sạch sẽ mà không cần một trong các antipotype của trình xây dựng đơn hoặc 29-arg. Trên thực tế, thực tế hộp thoại gui của bạn truy cập tất cả những điều đó hét lên "vi phạm nguyên tắc trách nhiệm duy nhất".
quang phổ

3

Như mọi người đã nói, một tài nguyên được chia sẻ - cụ thể là thứ không thể xử lý truy cập đồng thời.

Một ví dụ cụ thể mà tôi đã thấy, là Nhà văn chỉ mục tìm kiếm Lucene.


1
Chưa hết, IndexWriter không phải là người độc thân ...
Đánh dấu

3

Bạn có thể sử dụng Singleton khi triển khai mẫu Trạng thái (theo cách hiển thị trong sách GoF). Điều này là do các lớp Nhà nước cụ thể không có trạng thái của riêng chúng và thực hiện các hành động của chúng theo các lớp ngữ cảnh.

Bạn cũng có thể làm cho Tóm tắt Factory là một singleton.


Đây là trường hợp tôi đang xử lý trong một dự án. Tôi đã sử dụng một mẫu trạng thái để loại bỏ mã điều kiện lặp đi lặp lại khỏi các phương thức của bối cảnh. Nhà nước không có biến thể của riêng họ. Tuy nhiên, tôi đang ở trên hàng rào liên quan đến việc liệu tôi có nên biến họ thành người độc thân hay không. Mỗi khi trạng thái chuyển một thể hiện mới được khởi tạo. Điều này có vẻ lãng phí vì không có cách nào thể hiện có thể khác với trường hợp khác, (vì không có biến đối tượng). Tôi đang cố gắng tìm hiểu tại sao tôi không nên sử dụng nó.
kiwicomb123

1
@ kiwicomb123 Hãy cố gắng thực hiện setState()trách nhiệm của bạn trong việc quyết định chính sách tạo nhà nước. Nó giúp nếu ngôn ngữ lập trình của bạn hỗ trợ các mẫu hoặc generic. Thay vì Singleton, bạn có thể sử dụng mẫu Monostate , trong đó việc khởi tạo một đối tượng trạng thái kết thúc việc sử dụng lại cùng một đối tượng trạng thái toàn cục / tĩnh. Cú pháp thay đổi trạng thái có thể không thay đổi, vì người dùng của bạn không cần biết rằng trạng thái khởi tạo là Monostate.
Cileier Cormier

Được rồi vì vậy trong trạng thái của tôi, tôi chỉ có thể làm cho tất cả các phương thức tĩnh, vì vậy bất cứ khi nào một cá thể mới được tạo ra, nó không có cùng chi phí? Tôi hơi bối rối, tôi cần đọc về mẫu Monostate.
kiwicomb123

@ kiwicomb123 Không, Monostate không phải là làm cho tất cả các thành viên tĩnh. Tốt hơn là bạn đọc nó, sau đó kiểm tra SO cho các câu hỏi và câu trả lời liên quan.
Cileier Cormier

Tôi cảm thấy điều này nên có nhiều phiếu bầu hơn. Nhà máy trừu tượng là đủ phổ biến và vì các nhà máy không trạng thái, ổn định trong trạng thái không trạng thái và không thể được thực hiện bằng các phương thức tĩnh (trong Java) mà không bị quá tải, nên sử dụng singleton sẽ ổn.
DPM

3

Tài nguyên dùng chung. Đặc biệt là trong PHP, một lớp cơ sở dữ liệu, một lớp mẫu và một lớp kho tổng hợp biến toàn cục. Tất cả phải được chia sẻ bởi tất cả các mô-đun / lớp đang được sử dụng trong suốt mã.

Đó là cách sử dụng đối tượng thực sự -> lớp mẫu chứa mẫu trang đang được xây dựng và nó được định hình, thêm, thay đổi bởi các mô-đun đang thêm vào đầu ra trang. Nó phải được giữ như một trường hợp duy nhất để điều này có thể xảy ra, và cơ sở dữ liệu cũng vậy. Với một cơ sở dữ liệu được chia sẻ, tất cả các lớp của mô-đun có thể có quyền truy cập vào các truy vấn và nhận được chúng mà không cần phải chạy lại chúng.

Một biến đơn depot biến toàn cầu cung cấp cho bạn một kho biến toàn cầu, đáng tin cậy và dễ sử dụng. Nó dọn dẹp mã của bạn rất nhiều. Hãy tưởng tượng có tất cả các giá trị cấu hình trong một mảng trong một singleton như:

$gb->config['hostname']

hoặc có tất cả các giá trị ngôn ngữ trong một mảng như:

$gb->lang['ENTER_USER']

Khi kết thúc việc chạy mã cho trang, bạn sẽ nhận được, bây giờ là một sự trưởng thành:

$template

Singleton, một $gbsingleton có mảng lang để thay thế vào nó, và tất cả đầu ra được tải và sẵn sàng. Bạn chỉ cần thay thế chúng thành các khóa hiện có trong giá trị trang của đối tượng mẫu trưởng thành và sau đó cung cấp nó cho người dùng.

Ưu điểm lớn của việc này là bạn có thể thực hiện bất kỳ xử lý hậu kỳ nào bạn thích trên bất cứ thứ gì. Bạn có thể chuyển tất cả các giá trị ngôn ngữ sang google dịch hoặc dịch vụ dịch thuật khác và lấy lại chúng, và thay thế chúng vào vị trí của chúng, ví dụ như đã dịch. hoặc, bạn có thể thay thế trong cấu trúc trang hoặc chuỗi nội dung theo ý muốn.


21
Bạn có thể muốn chia câu trả lời của mình thành nhiều đoạn và chặn các đoạn mã để dễ đọc.
Justin

1

Nó có thể rất thực tế để cấu hình các mối quan tâm cơ sở hạ tầng cụ thể như các singletons hoặc các biến toàn cục. Ví dụ yêu thích của tôi về điều này là các khung Dependency Injection sử dụng các singletons để hoạt động như một điểm kết nối với khung.

Trong trường hợp này, bạn đang sử dụng một phụ thuộc vào cơ sở hạ tầng để đơn giản hóa việc sử dụng thư viện và tránh sự phức tạp không cần thiết.


0

Tôi sử dụng nó cho một đối tượng đóng gói các tham số dòng lệnh khi xử lý các mô đun có thể cắm được. Chương trình chính không biết các tham số dòng lệnh là gì đối với các mô-đun được tải (và thậm chí không biết mô-đun nào đang được tải). ví dụ: tải chính A, không cần bất kỳ tham số nào (vậy tại sao cần thêm một con trỏ / tham chiếu / bất cứ điều gì, tôi không chắc chắn - trông giống như ô nhiễm), sau đó tải các mô-đun X, Y và Z. Hai trong số này, giả sử X và Z, cần (hoặc chấp nhận) các tham số, vì vậy họ gọi lại cho singleton dòng lệnh để cho nó biết tham số nào sẽ chấp nhận và trong thời gian chạy họ gọi lại để tìm hiểu xem người dùng có thực sự đã chỉ định không của họ.

Theo nhiều cách, một singleton để xử lý các tham số CGI sẽ hoạt động tương tự nếu bạn chỉ sử dụng một quy trình cho mỗi truy vấn (các phương thức mod_ * khác không làm điều này, vì vậy nó sẽ rất tệ ở đó - do đó, đối số nói rằng bạn không nên ' t sử dụng singletons trong thế giới mod_cgi trong trường hợp bạn chuyển sang mod_perl hoặc bất cứ thế giới nào).


-1

Một ví dụ với mã, có lẽ.

Ở đây, ConcreteRegistry là một đơn vị trong trò chơi poker cho phép các hành vi trên toàn bộ cây gói truy cập vào một vài giao diện cốt lõi của trò chơi (ví dụ: mặt tiền cho mô hình, chế độ xem, bộ điều khiển, môi trường, v.v.):

http://www.edmundkirwan.com/servlet/fractal/cs1/frac-cs40.html

Ed.


1
Liên kết hiện đã bị hỏng, nhưng nếu bạn đang đăng ký xem thông tin trong một singleton, sẽ được truy cập trong toàn bộ ứng dụng, bạn đang thiếu điểm của MVC. Một khung nhìn được cập nhật bởi (và giao tiếp với) bộ điều khiển, sử dụng mô hình. Như có vẻ ở đây, nó có thể là một sự lạm dụng của Singleton và tái cấu trúc là theo thứ tự.
drharris

-9

1 - Một nhận xét về câu trả lời đầu tiên:

Tôi không đồng ý với lớp Logger tĩnh. điều này có thể thực tế cho việc thực hiện, nhưng nó không thể thay thế cho thử nghiệm đơn vị. Một lớp tĩnh không thể được thay thế bằng một bài kiểm tra kép. Nếu bạn không kiểm tra đơn vị, bạn sẽ không thấy vấn đề ở đây.

2 - Tôi cố gắng không tạo ra một singleton bằng tay. Tôi chỉ tạo một đối tượng đơn giản với các hàm tạo cho phép tôi đưa cộng tác viên vào đối tượng. Nếu tôi cần một singleton, tôi sẽ sử dụng khung inyection phụ thuộc (Spring.NET, Unity cho .NET, Spring cho Java) hoặc một số thứ khác.


11
Bạn nên bình luận về câu trả lời trực tiếp bằng cách nhấp vào liên kết ở cuối câu trả lời; Cách đó dễ hơn nhiều. Ngoài ra, câu trả lời bạn nhìn thấy ở đầu có lẽ không phải là đầu tiên. Câu trả lời được sắp xếp lại mọi lúc.
Ross

Tại sao bạn muốn đăng nhập thử nghiệm đơn vị?
Enerccio

Có một sự khác biệt rất lớn giữa "một lớp Logger tĩnh" và một thể hiện Logger tĩnh . Mẫu singleton không nói "làm cho lớp của bạn tĩnh", nó nói để truy cập vào thể hiện của một đối tượng tĩnh. Vì vậy, ví dụ, ILogger logger = Logger.SingleInstance();trong đó phương thức này là tĩnh và nó trả về một thể hiện được lưu trữ tĩnh của ILogger. Bạn đã sử dụng ví dụ về "khung tiêm phụ thuộc". Gần như tất cả các container DI đều là singletons; cấu hình của chúng được xác định tĩnh và cuối cùng được truy cập từ / được lưu trữ trong một giao diện nhà cung cấp dịch vụ duy nhất.
Jon Davis
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.