Câu hỏi Điều gì là xấu về những người độc thân? [đã đóng]


Các mẫu đơn là thành viên được thanh toán đầy đủ của GoF'S mẫu cuốn sách, nhưng gần đây nó dường như bị mồ côi bởi thế giới nhà phát triển. Tôi vẫn sử dụng khá nhiều người độc thân, đặc biệt là cho nhà máy lớp họcvà trong khi bạn phải cẩn thận một chút về các vấn đề đa luồng (như bất kỳ lớp nào thực sự), tôi không thấy lý do tại sao chúng quá khủng khiếp.

Stack Overflow đặc biệt có vẻ giả định rằng mọi người đều đồng ý rằng Singletons là ác. Tại sao?

Vui lòng hỗ trợ câu trả lời của bạn với "sự kiện, tài liệu tham khảo hoặc chuyên môn cụ thể"


1737


gốc


Tôi phải nói rằng bằng cách sử dụng một thiết kế singleton đã đốt cháy tôi gần đây như tôi đã cố gắng để thích ứng với mã. Khi tôi làm điều đó trong thời gian rảnh rỗi của tôi, tôi gần như quá lười biếng để cấu trúc lại điều này. Tin xấu cho năng suất. - Marcin
Có rất nhiều "khuyết điểm" trong các câu trả lời, nhưng tôi cũng muốn xem một số ví dụ hay về thời điểm mô hình tốt, để đối chiếu với những điều xấu ... - DGM
Tôi đã viết một bài đăng trên blog về chủ đề này vài tháng trước: jalf.dk/blog/2010/03/… - và để tôi nói thẳng. Tôi không thể nghĩ về một tình huống đơn lẻ mà một singleton là giải pháp đúng đắn. Điều đó không có nghĩa là một tình huống như vậy không tồn tại, nhưng ... gọi chúng là hiếm hoi là một sự nói dối. - jalf
@AdamSmith nó không có nghĩa là bạn có , nhưng nó có nghĩa là bạn có thể truy cập nó như thế. Và nếu bạn không có ý định truy cập nó như thế, thì có ít lý do để làm cho nó thành một singleton ngay từ đầu. Vì vậy, lập luận của bạn là có hiệu quả "không có hại trong việc tạo ra một singleton nếu chúng ta không đãi nó như một singleton. Ừ, tuyệt. Xe của tôi cũng không gây ô nhiễm nếu tôi không lái xe. Nhưng sau đó nó dễ dàng hơn để chỉ không có được một chiếc xe ở nơi đầu tiên. ;) (tiết lộ đầy đủ: Tôi thực sự không có xe hơi) - jalf
Phần tồi tệ nhất của toàn bộ chủ đề này là những người ghét những người độc thân hiếm khi đưa ra những gợi ý cụ thể về những gì để sử dụng thay thế. Các liên kết đến các bài báo và các blog tự xuất bản tất cả thông qua bài viết SO này, ví dụ, tiếp tục và về lý do tại sao không phải sử dụng singletons (và tất cả chúng đều là những lý do tuyệt vời), nhưng chúng cực kỳ mỏng manh khi thay thế. Rất nhiều handwaving, mặc dù. Những người trong chúng ta đang cố gắng dạy cho các lập trình viên mới tại sao không sử dụng các singletons không có nhiều counterexamples tốt của bên thứ ba để chỉ ra, chỉ những ví dụ giả tạo. Nó mệt mỏi. - Ti Strga


Các câu trả lời:


Diễn giải từ Brian Button:

  1. Chúng thường được sử dụng như một cá thể toàn cầu, tại sao điều đó lại xấu đến thế? Bởi vì bạn ẩn các phụ thuộc của ứng dụng của bạn trong mã của bạn, thay vì để lộ chúng thông qua các giao diện. Làm một cái gì đó toàn cầu để tránh đi qua nó là một mã mùi.

  2. Họ vi phạm nguyên tắc trách nhiệm duy nhất: bởi thực tế là họ kiểm soát sự sáng tạo và vòng đời của chính mình.

  3. Họ vốn đã gây ra mã phải chặt chẽ ghép đôi. Điều này làm cho giả mạo chúng trong thử nghiệm khá khó khăn trong nhiều trường hợp.

  4. Họ mang theo trạng thái xung quanh suốt đời của ứng dụng. Một hit để thử nghiệm kể từ khi bạn có thể kết thúc với một tình huống mà các xét nghiệm cần phải được đặt hàng mà là một không lớn không cho các bài kiểm tra đơn vị. Tại sao? Bởi vì mỗi bài kiểm tra đơn vị nên độc lập với nhau.


1148



Tôi không đông y vơi bạn. Vì nhận xét chỉ được phép có 600 ký tự, tôi đã viết một Bài đăng trên blog để nhận xét về điều này, vui lòng xem liên kết bên dưới. jorudolph.wordpress.com/2009/11/22/singleton-considerations - Johannes Rudolph
Ở điểm 1 và 4, tôi nghĩ rằng các single đơn giản là hữu ích, và trên thực tế gần như hoàn hảo cho việc lưu trữ dữ liệu (đặc biệt là từ một DB). Sự gia tăng hiệu suất vượt xa những phức tạp liên quan đến việc thử nghiệm mô hình đơn vị. - Dai Bok
@Dai Bok: "bộ nhớ đệm dữ liệu (đặc biệt là từ một DB)" sử dụng mô hình proxy để làm điều này ... - paxos1977
Wow, phản hồi tuyệt vời. Tôi có thể sử dụng từ ngữ quá khích động ở đây, vì vậy hãy nhớ rằng tôi đang trả lời một câu hỏi tiêu cực. Câu trả lời của tôi có nghĩa là một danh sách ngắn về các 'mô hình chống' xuất hiện từ việc sử dụng Singleton tồi tệ. Tiết lộ đầy đủ; Tôi cũng sử dụng Singletons theo thời gian. Có nhiều câu hỏi đặt ra trung lập hơn về SO sẽ tạo nên các diễn đàn tuyệt vời cho thời điểm Singletons có thể được coi là một ý tưởng hay. Ví dụ, stackoverflow.com/questions/228164/… - Jim Burger
Họ không phải là tuyệt vời cho bộ nhớ đệm trong một môi trường đa luồng. Bạn có thể dễ dàng đánh bại một bộ nhớ cache với nhiều chủ đề chiến đấu trên một nguồn lực hạn chế. [được duy trì bởi một singleton] - monksy


Singletons giải quyết một (và chỉ một) vấn đề.

Tài nguyên Contention.

Nếu bạn có một số tài nguyên

(1) chỉ có thể có một trường hợp duy nhất và

(2) bạn cần quản lý cá thể đơn lẻ đó,

bạn cần một singleton.

Không có nhiều ví dụ. Tệp nhật ký là tệp lớn nhất. Bạn không muốn chỉ từ bỏ một tệp nhật ký duy nhất. Bạn muốn tuôn ra, đồng bộ hóa và đóng nó đúng cách. Đây là một ví dụ về một tài nguyên được chia sẻ duy nhất phải được quản lý.

Thật hiếm khi bạn cần một singleton. Lý do họ xấu là họ cảm thấy như một toàn cầu và họ là thành viên được trả lương đầy đủ của GoF Mẫu thiết kế sách.

Khi bạn nghĩ rằng bạn cần một toàn cầu, có thể bạn đang mắc lỗi thiết kế khủng khiếp.


399



Phần cứng cũng là một ví dụ đúng không? Các hệ thống nhúng có rất nhiều phần cứng có thể sử dụng các trình đơn - hoặc có thể là một phần cứng lớn? <grin> - Jeff
Hoàn toàn đồng ý. Có rất nhiều quyết tâm "thực hành này là xấu" nói chuyện nổi xung quanh mà không có bất kỳ sự công nhận rằng thực tế có thể có vị trí của nó. Thông thường, thực hành chỉ "xấu" vì nó thường xuyên bị lạm dụng. Không có gì sai với mẫu Singleton miễn là nó được áp dụng một cách thích hợp. - Damovisa
Thực sự, đơn nguyên tắc là rất hiếm (và một hàng đợi máy in chắc chắn không phải là một, và không phải là một tập tin đăng nhập - xem log4j). Thường xuyên hơn không, phần cứng là một singleton bởi trùng hợp ngẫu nhiên chứ không phải theo nguyên tắc. Tất cả phần cứng kết nối với PC đều tốt nhất là một singleton ngẫu nhiên (nghĩ nhiều màn hình, chuột, máy in, card âm thanh). Ngay cả một máy dò hạt 500 đô la $ là một singleton bởi sự trùng hợp ngẫu nhiên và ngân sách - mà không áp dụng trong phần mềm, do đó: không có singleton. Trong viễn thông, không phải số điện thoại hay điện thoại vật lý đều là những người độc thân (nghĩ ISDN, trung tâm cuộc gọi). - digitalarbeiter
Phần cứng chỉ có thể có một thể hiện của nhiều loại tài nguyên, nhưng phần cứng không phải là phần mềm. Không có lý do gì mà một cổng nối tiếp đơn lẻ trên một bo mạch phát triển nên được mô hình hóa như một Singleton. Thật vậy, mô hình hóa nó như vậy sẽ chỉ làm cho nó khó khăn hơn để cổng vào hội đồng quản trị mới có hai cổng! - dash-tom-bang
Vì vậy, bạn sẽ viết hai lớp giống hệt nhau, sao chép rất nhiều mã, chỉ để bạn có thể có hai singletons đại diện cho hai cổng? Làm thế nào về việc chỉ sử dụng hai đối tượng SerialPort toàn cầu? Làm thế nào về không phải mô hình hóa phần cứng như các lớp học? Và tại sao bạn sẽ sử dụng các single, điều này cũng ngụ ý sự truy cập toàn cầu? Bạn có muốn mỗi chức năng trong mã của bạn để có thể truy cập vào cổng nối tiếp? - jalf


Một số snob mã hóa nhìn xuống chúng chỉ là một toàn cầu tôn vinh. Cũng giống như nhiều người ghét đi đến tuyên bố có những người khác ghét ý tưởng sử dụng toàn cầu. Tôi đã thấy một số nhà phát triển đi đến độ dài bất thường để tránh toàn cầu bởi vì họ xem xét sử dụng một như là một sự thừa nhận thất bại. Lạ nhưng có thật.

Trong thực tế Singleton mô hình chỉ là một kỹ thuật lập trình là một phần hữu ích trong bộ công cụ của các khái niệm. Theo thời gian bạn có thể tìm thấy nó là giải pháp lý tưởng và do đó sử dụng nó. Nhưng sử dụng nó chỉ để bạn có thể khoe khoang về việc sử dụng mẫu thiết kế cũng ngu ngốc như từ chối không bao giờ sử dụng nó bởi vì nó chỉ là toàn cầu.


307



Sự thất bại mà tôi thấy ở Singleton là những người sử dụng chúng thay vì hình cầu vì chúng bằng cách nào đó "tốt hơn". Vấn đề là (như tôi thấy nó), rằng những thứ mà Singleton mang đến bàn trong những trường hợp này là không liên quan. (Xây dựng-trên-sử dụng đầu tiên là tầm thường để thực hiện trong một không singleton, ví dụ, ngay cả khi nó không thực sự sử dụng constructor để làm điều đó.) - dash-tom-bang
Lý do "chúng tôi" nhìn xuống họ là "chúng tôi" rất thường xuyên thấy họ sử dụng sai, và cách quá thường xuyên. "Chúng tôi" biết rằng họ có vị trí của họ về nguyên nhân. - Bjarke Freund-Hansen
@Phil, Bạn nói "theo thời gian bạn có thể tìm thấy nó là giải pháp lý tưởng và vì vậy sử dụng nó". Ok, chính xác là trong cái nào trường hợp chúng ta sẽ tìm thấy một singleton hữu ích? - Pacerier
@Pacerier, bất cứ khi nào tất cả các điều kiện sau đây giữ: (1) bạn chỉ cần một cái gì đó, (2) bạn cần phải vượt qua một điều như một đối số trong một số lượng lớn các cuộc gọi phương thức, (3) bạn sẵn sàng chấp nhận cơ hội phải tái cấu trúc một ngày nào đó để đổi lấy việc giảm ngay lập tức kích thước và độ phức tạp của mã của bạn bằng cách không vượt qua những điều darn quanh mọi nơi. - antinome
Tôi không cảm thấy rằng điều này trả lời bất cứ điều gì, nó chỉ nói rằng 'đôi khi nó có thể phù hợp, lần khác nó có thể không'. OK, nhưng tại sao, và khi nào? Điều gì làm cho câu trả lời này nhiều hơn một đối số để kiểm duyệt? - Guildenstern


Misko Hevery, từ Google, có một số bài viết thú vị về chính xác chủ đề này ...

Singletons là Kẻ dối trá về bệnh lý có một ví dụ thử nghiệm đơn vị minh họa cách thức các singleton có thể gây khó khăn cho việc tìm ra các chuỗi phụ thuộc và bắt đầu hoặc thử nghiệm một ứng dụng. Đó là một ví dụ khá khắc nghiệt về lạm dụng, nhưng điểm mà anh ta đưa ra vẫn hợp lệ:

Singletons chẳng là gì ngoài tình trạng toàn cầu. Trạng thái toàn cầu làm cho nó để các đối tượng của bạn có thể bí mật nắm giữ những thứ không được khai báo trong API của chúng, và kết quả là, Singletons làm cho các API của bạn trở thành những kẻ nói dối bệnh lý.

Trường hợp có tất cả Singletons Gone làm cho điểm mà tiêm phụ thuộc đã làm cho nó dễ dàng để có được trường hợp để các nhà xây dựng có yêu cầu họ, làm giảm bớt nhu cầu cơ bản đằng sau những người xấu, toàn cầu Singletons đã chết trong bài viết đầu tiên.


200



Các bài báo của Misko về chủ đề là điều tốt nhất đang diễn ra trên đó vào lúc này. - Chris Mayer
Liên kết đầu tiên không thực sự giải quyết vấn đề với các singletons, mà đúng hơn là giả định một sự phụ thuộc tĩnh bên trong lớp. Có thể sửa chữa ví dụ đã cho bằng cách truyền các tham số, nhưng vẫn sử dụng các trình đơn. - DGM
@ DGM: Chính xác - trên thực tế, có một sự ngắt kết nối hợp lý rất lớn giữa phần 'lý do' của bài viết và phần 'Singletons là nguyên nhân'. - Harper Shelby
Bài báo thẻ tín dụng của Misko là một cực ví dụ về lạm dụng mẫu này. - Alex
Đọc bài báo thứ hai Singletons thực sự là một phần của mô hình đối tượng được mô tả. Tuy nhiên, thay vì có thể truy cập trên toàn cầu, chúng là riêng tư đối với các đối tượng Factory. - FruitBreak


Tôi nghĩ sự nhầm lẫn là do thực tế là mọi người không biết ứng dụng thực sự của mẫu Singleton. Tôi không thể nhấn mạnh điều này. Singleton mới là không phải một mô hình để bọc hình cầu. Mẫu Singleton chỉ nên được sử dụng để đảm bảo rằng một và chỉ một thể hiện của một lớp nhất định tồn tại trong thời gian chạy.

Mọi người nghĩ Singleton là ác bởi vì họ đang sử dụng nó cho globals. Đó là vì sự nhầm lẫn này mà Singleton nhìn xuống. Làm ơn đừng nhầm lẫn giữa Singletons và globals. Nếu được sử dụng cho mục đích nó đã được dự định cho, bạn sẽ đạt được lợi ích cực đoan từ mô hình Singleton.


103



Đó là một ví dụ, có sẵn trong suốt ứng dụng? Oh. Toàn cầu. "Singleton là không phải một mô hình để bọc hình cầu "là ngây thơ hoặc gây hiểu nhầm, như theo định nghĩa, mẫu bao bọc một lớp xung quanh một cá thể chung. - cHao
Tất nhiên bạn có thể tự do tạo một thể hiện của lớp khi ứng dụng của bạn bắt đầu, và tiêm cá thể đó, thông qua một giao diện, vào bất cứ thứ gì sử dụng nó. Việc thực hiện không nên quan tâm rằng chỉ có thể có một. - Scott Whitlock
@ David: Thực sự là không, cuối cùng. Chắc chắn, bạn không được tự ý thay thế thể hiện bằng một trường hợp khác. (Ngoại trừ những khoảnh khắc gây cảm động khi bạn làm. Tôi đã thực sự nhìn thấy setInstance Tuy nhiên, điều đó hầu như không quan trọng - rằng weenie rằng "cần" một singleton cũng không biết một điều kỳ quặc về việc đóng gói hoặc những gì sai với trạng thái toàn cầu có thể thay đổi được, vì vậy anh ta đã giúp đỡ mọi người. Độc thân. cánh đồng. (Và có, điều này xảy ra. nhiều. Gần như mọi singleton tôi từng thấy trong tự nhiên đều có thể thay đổi theo thiết kế, và thường xuyên gây khó chịu.) - cHao
@ David: Đến một mức độ lớn, chúng tôi đã có. "Ưu tiên thành phần trên thừa kế" đã là một điều khá lâu rồi. Khi thừa kế Là rõ ràng là giải pháp tốt nhất, tuy nhiên, bạn tất nhiên là miễn phí để sử dụng nó. Điều tương tự với singletons, globals, threading, goto, v.v. Họ có thể công việc trong nhiều trường hợp, nhưng thẳng thắn, "công trình" là không đủ - nếu bạn muốn chống lại sự khôn ngoan thông thường, bạn đã có thể chứng minh cách tiếp cận của bạn tốt hơn tốt hơn so với các giải pháp thông thường. Và tôi vẫn chưa thấy trường hợp như vậy đối với mẫu Singleton. - cHao
Vì sợ rằng chúng tôi nói chuyện qua nhau, tôi không chỉ nói về một trường hợp có sẵn trên toàn cầu. Có rất nhiều trường hợp cho điều đó. Những gì tôi đang nói về (đặc biệt là khi tôi nói "capital-S Singleton") là mẫu Singleton của GoF, mà nhúng rằng cá thể toàn cầu duy nhất trong lớp chính nó, phơi bày nó thông qua một getInstance hoặc phương pháp được đặt tên tương tự, và ngăn chặn sự tồn tại của một cá thể thứ hai. Thành thật mà nói, vào thời điểm đó, bạn cũng có thể thậm chí không có một ví dụ. - cHao


Một điều khá xấu về những người độc thân là bạn không thể mở rộng chúng một cách dễ dàng. Về cơ bản bạn phải xây dựng trong một số loại -mô hình trang trí hoặc một số điều như vậy nếu bạn muốn thay đổi hành vi của họ. Ngoài ra, nếu một ngày bạn muốn có nhiều cách để làm điều đó, nó có thể khá đau đớn để thay đổi, tùy thuộc vào cách bạn đặt ra mã của bạn.

Một điều cần lưu ý, nếu bạn sử dụng những người độc thân, hãy cố gắng truyền chúng cho bất cứ ai cần chúng hơn là để họ truy cập trực tiếp ... Nếu không, nếu bạn chọn có nhiều cách để làm điều mà singleton thực hiện, nó sẽ là khá khó thay đổi khi mỗi lớp nhúng phụ thuộc nếu nó truy cập trực tiếp vào singleton.

Nên về cơ bản:

public MyConstructor(Singleton singleton) {
    this.singleton = singleton;
}

thay vì:

public MyConstructor() {
    this.singleton = Singleton.getInstance();
}

Tôi tin rằng kiểu mẫu này được gọi là tiêm phụ thuộc và thường được coi là một điều tốt.

Giống như bất kỳ mô hình mặc dù ... Hãy suy nghĩ về nó và xem xét nếu việc sử dụng nó trong tình huống nhất định là không thích hợp hay không ... Quy tắc được thực hiện để được chia thường, và mẫu không nên được áp dụng willy nilly mà không cần suy nghĩ.


71



Heh, nếu bạn làm điều này ở khắp mọi nơi, sau đó bạn sẽ phải vượt qua một tham chiếu đến singelton ở khắp mọi nơi cũng có, và do đó bạn không có một singleton nữa. :) (Mà thường là một điều tốt IMO.) - Bjarke Freund-Hansen
@ BjarkeFreund-Hansen - Vô nghĩa, bạn đang nói về cái gì vậy? Một singleton đơn giản là một thể hiện của một lớp được instatiated một lần. Tham chiếu như một Singleton không sao chép đối tượng thực sự, nó chỉ tham chiếu nó - bạn vẫn có cùng một đối tượng (đọc: Singleton). - M. Mimpen
@ M.Mimpen: Không, một Singleton vốn-S (đó là những gì đang được thảo luận ở đây) là một thể hiện của một lớp học mà (a) đảm bảo rằng chỉ có một cá thể sẽ tồn tại, và (b) được truy cập thông qua điểm truy cập toàn cục được tích hợp sẵn của lớp. Nếu bạn đã tuyên bố rằng không có gì nên gọi getInstance(), sau đó (b) không còn đúng nữa. - cHao
@cao Tôi không theo bạn hoặc bạn không hiểu người mà tôi bình luận - đó là Bjarke Freund-Hansen. Bjarke nói rằng có một số tham chiếu của một kết quả singleton có một số đơn. Điều đó chắc chắn không đúng vì không có bản sao sâu. - M. Mimpen
@ M.Mimpen: Tôi lấy bình luận của mình để tham khảo thêm về hiệu ứng ngữ nghĩa. Khi bạn gọi điện ngoài vòng pháp luật getInstance(), bạn đã ném ra một sự khác biệt hữu ích giữa mẫu Singleton và một tham chiếu thông thường. Theo như phần còn lại của mã là có liên quan, singleness không còn là tài sản. Chỉ người gọi getInstance() bao giờ cần phải biết hoặc thậm chí quan tâm có bao nhiêu trường hợp có. Chỉ với một người gọi, chi phí nhiều hơn trong nỗ lực và tính linh hoạt của lớp để thực thi một cách đáng tin cậy tính đơn lẻ hơn là để người gọi chỉ cần lưu trữ một tham chiếu và sử dụng lại nó. - cHao


Mẫu đơn không phải là vấn đề. Vấn đề là mô hình thường được sử dụng bởi những người phát triển phần mềm với các công cụ hướng đối tượng mà không cần nắm vững các khái niệm OO. Khi các singleton được giới thiệu trong ngữ cảnh này, chúng có khuynh hướng phát triển thành các lớp không thể quản lý có chứa các phương thức trợ giúp cho mỗi lần sử dụng nhỏ.

Singletons cũng là một vấn đề từ góc nhìn thử nghiệm. Họ có xu hướng làm cho các bài kiểm tra đơn vị bị cô lập khó viết. Đảo ngược kiểm soát (IoC) và tiêm phụ thuộc là các mẫu có nghĩa là để khắc phục vấn đề này theo cách thức hướng đối tượng tự vay để thử nghiệm đơn vị.

Trong một rác thu gom môi trường đơn có thể nhanh chóng trở thành một vấn đề liên quan đến quản lý bộ nhớ.

Ngoài ra còn có các kịch bản đa luồng, nơi đơn có thể trở thành một nút cổ chai cũng như một vấn đề đồng bộ hóa.


65



tôi biết nó là chủ đề cũ nhiều năm. hi @Kimoz u cho biết: - singletons có thể nhanh chóng trở thành một vấn đề liên quan đến quản lý bộ nhớ. muốn giải thích chi tiết hơn về loại vấn đề có thể xảy ra liên quan đến việc thu gom đơn lẻ và rác thải. - Thomas
@Kimoz, Câu hỏi đang hỏi "Tại sao mẫu đơn không phải là một vấn đề trong chính nó?" và bạn chỉ đơn thuần lặp lại vấn đề nhưng không cung cấp một trường hợp sử dụng hợp lệ nào của mẫu đơn. - Pacerier
@Thomas, bởi vì một singleton theo định nghĩa tồn tại chỉ trong một ví dụ. Vì vậy, nó thường phức tạp để gán tham chiếu duy nhất cho null. Nó có thể được thực hiện, nhưng nó có nghĩa là bạn hoàn toàn kiểm soát điểm mà sau đó singleton không được sử dụng trong ứng dụng của bạn. Và điều này là hiếm, và thường hoàn toàn trái ngược với những gì người đam mê singleton đang tìm kiếm: một cách đơn giản để tạo ra một cá thể đơn lẻ luôn luôn có thể truy cập. Trên một số DI framworks như Guice hay Dagger, không thể loại bỏ một singleton và nó vẫn tồn tại mãi mãi trong ký ức. (Mặc dù container cung cấp đơn là tốt hơn nhiều so với nhà làm). - Snicolas


Một singleton được thực hiện bằng cách sử dụng một phương thức tĩnh. Các phương pháp tĩnh có thể tránh được bởi những người thực hiện kiểm thử đơn vị vì chúng không thể bị nhạo báng hoặc bị nhốt. Hầu hết mọi người trên trang web này là những người ủng hộ lớn về thử nghiệm đơn vị. Quy ước được chấp nhận phổ biến nhất để tránh chúng là sử dụng đảo ngược kiểm soát mẫu.


52



Điều đó nghe có vẻ giống như một vấn đề với thử nghiệm đơn vị có thể kiểm tra các đối tượng (đơn vị), hàm (đơn vị), toàn bộ thư viện (đơn vị), nhưng thất bại với bất kỳ thứ gì tĩnh trong lớp (cũng là đơn vị). - v010dya
không phải là bạn giả sử để moc tất cả các tài liệu tham khảo bên ngoài anyway? Nếu bạn đang có, sau đó là một vấn đề để moc singleton, nếu không, là bạn thực sự làm thử nghiệm đơn vị? - Dainius
@Dainius: Mocking các phiên bản ít rắc rối hơn nhiều so với các lớp mô phỏng. Bạn có thể trích xuất lớp học theo thử nghiệm từ phần còn lại của ứng dụng và kiểm tra bằng giả Singleton lớp học. Tuy nhiên, điều đó làm phức tạp quá trình thử nghiệm. Đối với một, bây giờ bạn cần để có thể dỡ bỏ các lớp theo ý muốn (không thực sự là một lựa chọn trong hầu hết các ngôn ngữ), hoặc bắt đầu một máy ảo mới cho mỗi bài kiểm tra (đọc: kiểm tra có thể mất hàng ngàn lần). Đối với hai, mặc dù, sự phụ thuộc vào Singleton là một chi tiết triển khai hiện đang bị rò rỉ trên tất cả các thử nghiệm của bạn. - cHao
Powermock có thể giả lập công cụ tĩnh. - Snicolas


Singletons cũng tệ khi nói đến phân nhóm. Bởi vì sau đó, bạn không có "chính xác một singleton" trong ứng dụng của bạn nữa.

Xem xét tình huống sau: Là nhà phát triển, bạn phải tạo một ứng dụng web truy cập cơ sở dữ liệu. Để đảm bảo rằng các cuộc gọi cơ sở dữ liệu đồng thời không xung đột lẫn nhau, bạn tạo một chuỗi lưu SingletonDao:

public class SingletonDao {
    // songleton's static variable and getInstance() method etc. omitted
    public void writeXYZ(...){
        synchronized(...){
            // some database writing operations...
        }
    }
}

Vì vậy, bạn chắc chắn rằng chỉ có một singleton trong ứng dụng của bạn tồn tại và tất cả các cơ sở dữ liệu đi qua này và chỉ SingletonDao. Môi trường sản xuất của bạn bây giờ trông như thế này: Single Singleton

Mọi thứ đều tốt đẹp cho đến nay.

Bây giờ, hãy xem xét bạn muốn thiết lập nhiều phiên bản ứng dụng web của bạn trong một cụm. Bây giờ, bạn đột nhiên có một cái gì đó như thế này:

Many singletons

Nghe có vẻ kỳ lạ, nhưng bây giờ bạn có nhiều đơn trong ứng dụng của bạn. Và đó là chính xác những gì một singleton không được cho là: Có nhiều đối tượng của nó. Điều này đặc biệt xấu nếu bạn, như trong ví dụ này, muốn thực hiện các cuộc gọi được đồng bộ hóa với một cơ sở dữ liệu.

Tất nhiên đây là một ví dụ về một cách sử dụng xấu của một singleton. Nhưng thông điệp của ví dụ này là: Bạn không thể tin tưởng rằng có chính xác một ví dụ của một singleton trong ứng dụng của bạn - đặc biệt là khi nói đến phân cụm.


42



nếu bạn không biết làm thế nào để thực hiện singleton, bạn không nên làm điều đó. Nếu bạn không biết bạn đang làm gì, bạn nên tìm điều đó trước, và chỉ sau đó mới làm những gì bạn cần. - Dainius
Điều này thật thú vị, tôi có một câu hỏi. Vậy chính xác là vấn đề gì nếu singletons - mỗi máy trên một máy tính khác nhau / JVM - đang kết nối với một cơ sở dữ liệu duy nhất? Phạm vi Singletons chỉ dành cho JVM cụ thể đó và điều đó vẫn đúng ngay cả trong một cụm. Thay vì chỉ nói một cách triết học rằng tình huống cụ thể này là xấu bởi vì mục đích của chúng tôi là một đối tượng đơn lẻ, tôi rất vui khi thấy bất kỳ vấn đề kỹ thuật nào có thể phát sinh do sự sắp xếp này. - Saurabh Patil