Sự khác biệt giữa lớp tĩnh và mẫu đơn?


1768

Sự khác biệt thực sự (nghĩa là thực tế) tồn tại giữa một lớp tĩnh và một mẫu đơn?

Cả hai đều có thể được gọi mà không cần khởi tạo, cả hai chỉ cung cấp một "Trường hợp" và cả hai đều không an toàn cho chuỗi. Có sự khác biệt nào khác không?


4
Tùy thuộc vào việc triển khai ngôn ngữ và các kiểu sử dụng của bạn, Singleton có thể kém hiệu quả hơn do phải gọi getInstance()phương thức mỗi lần bạn muốn sử dụng nó (mặc dù có thể trong hầu hết các trường hợp không thành vấn đề ).
quá nhiều php

5
Có rất nhiều câu trả lời rồi. Nó thực sự là một singletonđối tượng trong đó staticcác phương thức chỉ là các hàm, một thực thể không OO.
fastcodejava

4
Phụ thuộc vào việc triển khai .. csharpindepth.com/Articles/General/Singleton.aspx
VJAI

4
Có một sự khác biệt khi bạn muốn cho phép các bên thứ ba cung cấp việc triển khai lớp. Trong trường hợp này, bạn thường cần một mẫu Factory. Xem ag xuất sắc.wordpress.com / 2013/10/08 / Mạnh
AgilePro

IMO câu trả lời này tổng hợp rất tốt stackoverflow.com/questions/14097656/NH
Dave

Câu trả lời:


1251

Điều gì khiến bạn nói rằng một singleton hoặc một phương thức tĩnh không an toàn cho luồng? Thông thường cả hai nên được thực hiện để an toàn chủ đề.

Sự khác biệt lớn giữa một singleton và một loạt các phương thức tĩnh là các singleton có thể thực hiện các giao diện (hoặc xuất phát từ các lớp cơ sở hữu ích, mặc dù điều đó ít phổ biến hơn, theo kinh nghiệm của tôi), vì vậy bạn có thể vượt qua singleton như thể nó "chỉ là một cái khác " thực hiện.


29
Chà, nếu bạn thích nó, không phải là chủ đề an toàn, bạn phải làm cho chúng là chủ đề an toàn, cả hai, vì vậy không có sự khác biệt ở đó.
Jorge Córdoba

119
Bạn có thể đưa ra một ví dụ về một cái gì đó vốn là chủ đề an toàn, ngoài các loại không thay đổi?
Jon Skeet

26
Đối với Skeet: Mọi người nói rằng singleton không phải là chủ đề an toàn có nghĩa là một singleton được chia sẻ giữa các luồng không cần thiết mọi lúc, trong khi các đối tượng ngăn xếp được chia sẻ khi bạn cần chúng, điều đó có nghĩa là bạn không phải thực hiện đồng bộ hóa không cần thiết.

45
@Geek: Hãy tưởng tượng singleton thực hiện một giao diện Foovà bạn có một phương thức lấy Footham số làm tham số. Với thiết lập đó, người gọi có thể chọn sử dụng singleton làm triển khai - hoặc họ có thể sử dụng một triển khai khác. Phương pháp được tách rời khỏi singleton. So sánh với tình huống trong đó lớp chỉ có các phương thức tĩnh - mọi đoạn mã muốn gọi các phương thức đó được liên kết chặt chẽ với lớp, bởi vì nó cần chỉ định lớp nào chứa các phương thức tĩnh.
Jon Skeet

10
@AmirBareket: Mặc dù vậy, nó không phải là một mẫu đơn theo mẫu thiết kế singleton - nếu bản thân lớp cho phép tạo ra nhiều trường hợp, thì đó không phải là IMO đơn lẻ, bất kể nhà máy làm gì.
Jon Skeet

476

Câu trả lời thực sự là của Jon Skeet, trên một diễn đàn khác ở đây .

Một singleton cho phép truy cập vào một thể hiện được tạo duy nhất - thể hiện đó (hay đúng hơn là một tham chiếu đến thể hiện đó) có thể được truyền dưới dạng tham số cho các phương thức khác và được coi như một đối tượng bình thường.

Một lớp tĩnh chỉ cho phép các phương thức tĩnh.


64
Tuy nhiên, tại sao bạn lại chuyển một Singleton làm tham số, nếu bạn có thể truy cập cùng một thể hiện từ mọi nơi bằng cách gọi phương thức getInstance () tĩnh?
Henrique Ordine

23
@HenriqueOrdine Vì vậy, nó có thể phù hợp với mã hiện có và cung cấp một giao diện?

6
@HenriqueOrdine Họ đang nói về lớp tĩnh, không phải là lớp có phương thức tĩnh. Lớp tĩnh không thể được khởi tạo. Tuy nhiên, nếu bạn truyền một thể hiện của lớp (không tĩnh) có chứa các phương thức tĩnh, bạn không thể gọi các phương thức tĩnh trên một thể hiện.
Goran

3
Lớp tĩnh là gì? Ít nhất là trong Java, không có điều đó.
Henrique Ordine

16
@Goran Ban đầu tôi rất bối rối trước cách diễn đạt của bạn. Bạn nói "bạn không thể gọi các phương thức tĩnh trên một ví dụ". Tôi đọc là "nếu bạn có một tham chiếu đến một đối tượng được khởi tạo, bạn không thể gọi bất kỳ phương thức tĩnh nào mà nó có thể có." Đó là tất nhiên, không chính xác. Sau khi đọc lại một vài lần tôi nghĩ bạn có nghĩa là "từ bên trong các phương thức tĩnh, bạn không thể truy cập các đối tượng không tĩnh trong lớp", điều này là chính xác. Muốn làm rõ rằng đối với bất kỳ ai mới biết những khái niệm này, người bắt gặp câu trả lời này và đọc bình luận của bạn.
Andrew Steitz

359
  1. Các đối tượng đơn lẻ được lưu trữ trong Heap , nhưng các đối tượng tĩnh được lưu trữ trong ngăn xếp .
  2. Chúng ta có thể sao chép (nếu người thiết kế không cho phép nó) đối tượng singleton, nhưng chúng ta không thể sao chép đối tượng lớp tĩnh.
  3. Các lớp Singleton tuân theo OOP (nguyên tắc hướng đối tượng), các lớp tĩnh thì không.
  4. Chúng ta có thể triển khai một interfacelớp Singleton, nhưng các phương thức tĩnh của một lớp (hoặc ví dụ C # static class) không thể.

99
Phát biểu thứ hai là sai. Chúng ta không thể nhân bản đối tượng Singleton. Thực hiện Singleton phải từ chối điều này. Nếu bạn thực sự có thể nhân bản Singleton, thì đó không phải là Singleton.
Alexander Yancharuk

19
Đây là câu trả lời không chính xác cho Java: cả singleton và static đều không sử dụng stack.
AgilePro

72
# 1 không quan trọng. # 2 mô tả một triển khai bị lỗi. # 3 là hoàn toàn vô lý.
Casey

31
Làm thế nào có thể lưu trữ đối tượng tĩnh trong ngăn xếp? Khung ngăn xếp mới được tạo khi bạn gọi một phương thức, nó lưu các biến cục bộ của phương thức, khung ngăn xếp này bị loại bỏ khi phương thức trả về và các biến cục bộ đó bị mất. Chắc chắn stack rất nhanh, nhưng nó không phù hợp để lưu trữ các đối tượng tĩnh.
mike_m

23
Tôi không thể hiểu số lượng upvote trên cái này. 1) Tại sao Singleton phải được lưu trữ trong ngăn xếp? Trong các ngôn ngữ được quản lý như dữ liệu C # hoặc Java được lưu trữ trong một đống được quản lý, ngoại trừ các biến / tham số của phương thức cục bộ. 2) Nếu bạn có thể sao chép nó, thì đó không phải là một singleton được triển khai đúng cách. 3) Singleton được gọi là mẫu chống OOP; tức là một cái gì đó mà bạn nên tránh nếu có thể. 4) Đây là điều duy nhất đúng.
Groo

152

Mẫu Singleton có một số lợi thế so với các lớp tĩnh. Đầu tiên, một singleton có thể mở rộng các lớp và thực hiện các giao diện, trong khi một lớp tĩnh không thể (nó có thể mở rộng các lớp, nhưng nó không kế thừa các thành viên thể hiện của chúng). Một singleton có thể được khởi tạo một cách lười biếng hoặc không đồng bộ trong khi một lớp tĩnh thường được khởi tạo khi nó được tải lần đầu tiên, dẫn đến các vấn đề về trình nạp lớp tiềm năng. Tuy nhiên, ưu điểm quan trọng nhất là các singletons có thể được xử lý đa hình mà không buộc người dùng của họ cho rằng chỉ có một trường hợp.


10
+1 cho điểm tốt, thực dụng. Mô hình Singleton được sử dụng quá mức nói chung, nhưng có một vài tình huống phù hợp. Xem thêm: ag xuất sắc.wordpress.com / 2013/10/08 / từ
AgilePro

3
Bạn đã đúng về lợi thế của đa hình. Đây là điểm quan trọng nhất
Ahmad

Lớp tĩnh lồng nhau có thể thực hiện giao diện. Hãy thử mã hóa nó, sẽ làm việc. Tôi có thể biên dịch mã mà không có bất kỳ lỗi nào.
nanosoft

75

staticcác lớp học không dành cho bất cứ thứ gì cần nhà nước. Nó rất hữu ích để đặt một loạt các chức năng với nhau tức là Math(hoặc Utilstrong các dự án). Vì vậy, tên lớp chỉ cho chúng ta một đầu mối nơi chúng ta có thể tìm thấy các hàm và không có gì nữa.

Singletonlà mô hình yêu thích của tôi và tôi sử dụng nó để quản lý một cái gì đó tại một điểm duy nhất. Nó linh hoạt hơn staticcác lớp và có thể duy trì trạng thái của nó. Nó có thể thực hiện các giao diện, kế thừa từ các lớp khác và cho phép kế thừa.

Quy tắc của tôi để chọn giữa staticsingleton:

Nếu có một loạt các chức năng nên được giữ cùng nhau, thì đó staticlà sự lựa chọn. Bất cứ điều gì khác cần truy cập duy nhất vào một số tài nguyên, có thể được thực hiện như một singleton.


16
Tại sao các lớp tĩnh không nên làm bất cứ điều gì cần lưu trạng thái?
Đã xem

12
@Trisped: Bạn không kiểm soát chính xác việc khởi tạo cũng như hoàn thiện.
Xaqron

7
bạn đã mất tôi tại "Singleton là mẫu yêu thích của tôi". Singleton là một góc sắc nét đến mức nó nên được coi là một mô hình chống cũng như một mô hình. Các lớp cũng có thể có các trạng thái tĩnh, đó cũng là truy cập đơn, nếu bất kỳ trạng thái tĩnh nào là "truy cập đơn" hơn so với singletons vì hầu hết các triển khai đơn lẻ đều bị hỏng. bạn có thể nhân bản singleton, trong khi tĩnh được định nghĩa là duy nhất.
PoweredByRice

1
Nó có nghĩa là gì để duy trì nhà nước? Nhà nước là gì?
Kyle Delaney

2
@KyleDelaney: Đơn giản Statelà sự kết hợp các thuộc tính khác nhau của một đối tượng thường thay đổi theo thời gian. Bạn có thể Google cho định nghĩa chính thức.
Xaqron

65

Lớp tĩnh: -

  1. Bạn không thể tạo thể hiện của lớp tĩnh.

  2. Được tải tự động bởi thời gian chạy ngôn ngữ chung .NET Framework (CLR) khi chương trình hoặc không gian tên chứa lớp được tải.

  3. Lớp tĩnh không thể có hàm tạo.

  4. Chúng ta không thể truyền lớp tĩnh cho phương thức.

  5. Chúng ta không thể kế thừa lớp Tĩnh cho một lớp Tĩnh khác trong C #.

  6. Một lớp có tất cả các phương thức tĩnh.

  7. Hiệu suất tốt hơn (phương thức tĩnh được liên kết theo thời gian biên dịch)

Người độc thân: -

  1. Bạn có thể tạo một thể hiện của đối tượng và sử dụng lại nó.

  2. Ví dụ Singleton được tạo lần đầu tiên khi người dùng yêu cầu.

  3. Lớp Singleton có thể có constructor.

  4. Bạn có thể tạo đối tượng của lớp singleton và truyền nó cho phương thức.

  5. Lớp Singleton không nói bất kỳ hạn chế nào của Kế thừa.

  6. Chúng ta có thể loại bỏ các đối tượng của một lớp đơn nhưng không phải là lớp tĩnh.

  7. Phương pháp có thể được ghi đè.

  8. Có thể lười tải khi cần (các lớp tĩnh luôn được tải).

  9. Chúng ta có thể thực hiện giao diện (lớp tĩnh không thể thực hiện giao diện).


13
Các lớp tĩnh có các hàm tạo: msdn.microsoft.com/en-us/l
Library / k9x6w0hc.aspx

2
Có, tĩnh có thể có hàm tạo bên trong lớp đó. Điều này được gọi khi bất kỳ phương thức tĩnh nào trong lớp được gọi.
rahulmr

Đối với singleton về thời gian biên dịch, nó được lưu trữ trong bộ nhớ HEAP nhưng nếu nó được khởi tạo một lần thì nó có được lưu trong STACK không?
Shining_Dev

@Lum_Dev Không. Bất kỳ trường hợp đơn lẻ nào là một thể hiện đối tượng vào cuối ngày. Nó sẽ được lưu trữ trên đống mà không có nghi ngờ.
RBT

1
@rahulmr Phân biệt quan trọng: hàm tạo cũng được gọi trước khi thể hiện đầu tiên (chỉ AKA) được tạo.
CoolOppo

53

Một lớp tĩnh là một lớp chỉ có các phương thức tĩnh, trong đó một từ tốt hơn sẽ là "hàm". Phong cách thiết kế thể hiện trong một lớp tĩnh hoàn toàn là thủ tục.

Singleton, mặt khác, là một mẫu cụ thể cho thiết kế OO. Nó là một thể hiện của một đối tượng (với tất cả các khả năng vốn có trong đó, chẳng hạn như đa hình), với một quy trình tạo đảm bảo rằng chỉ có một thể hiện của vai trò cụ thể đó trong toàn bộ thời gian tồn tại của nó.


1
tính đa hình hoàn toàn không xuất hiện với các singletons

32
Vì vậy bạn nghĩ. Tôi nghĩ khác. ;) Ví dụ, hãy tưởng tượng một nhà máy đơn lẻ trả về một giao diện. Bạn biết rằng bạn sẽ nhận được một ISingleton (và nó là cùng một thứ mãi mãi) nhưng không nhất thiết phải thực hiện.
Morendil

Lớp tĩnh lồng nhau cũng có thể có các phương thức cá thể, nó không bị hạn chế chỉ có các phương thức tĩnh .. Mã hóa nó và bạn có thể thấy.
nanosoft

Trong các ngôn ngữ có mô hình đối tượng đẹp hơn (ví dụ: Ruby), các lớp cũng là đối tượng. Khía cạnh "hoàn toàn thủ tục" của một lớp tĩnh là một hạn chế tùy ý áp đặt bởi ngôn ngữ.
Tối đa

36

Trong mẫu singleton, bạn có thể tạo singleton như một thể hiện của loại dẫn xuất, bạn không thể làm điều đó với một lớp tĩnh.

Ví dụ nhanh:

if( useD3D )
    IRenderer::instance = new D3DRenderer
else
    IRenderer::instance = new OpenGLRenderer

39
Nó không thực sự là một mẫu đơn, trông giống như nhà máy đối với tôi.
vava

10
Không thực sự, sự khác biệt cơ bản giữa hai là Singleton sẽ "lưu trữ" đối tượng duy nhất của nó và tiếp tục trả về (một tham chiếu đến) cùng một đối tượng. Mẫu Factory sẽ tạo các thể hiện mới.
Huyền bí

12
Sau đó, nó là proxy-singleton :)
vava

3
Hmm, tôi biết nhiều loại Singleton như MonoState.
Huppie

ví dụ là mô hình nhà máy
Rajavel D

26

Để mở rộng câu trả lời của Jon Skeet

Sự khác biệt lớn giữa một singleton và một loạt các phương thức tĩnh là các singleton có thể thực hiện các giao diện (hoặc xuất phát từ các lớp cơ sở hữu ích, mặc dù đó là IME ít phổ biến hơn), vì vậy bạn có thể chuyển qua singleton như thể nó là "triển khai" khác.

Singletons dễ làm việc hơn khi đơn vị kiểm tra một lớp. Bất cứ nơi nào bạn vượt qua singletons như một tham số (hàm tạo, setters hoặc phương thức), bạn có thể thay thế một phiên bản bị nhạo báng hoặc sơ khai của singleton.


Tôi không nghĩ rằng bạn có thể trực tiếp chế giễu một người độc thân. Bạn sẽ không phải khai báo một giao diện mà cả lớp đơn và lớp giả đều thực hiện chứ?
Ellen Spertus

@espertus Tại sao bạn không thể chế nhạo singleton của bạn? Ví dụ sử dụng mockito MySingleton mockOfMySingleton = mock(MySingleton.class).
Mike Rylander

bạn nói đúng, bạn có thể chế giễu nó bằng các công cụ như mockito sử dụng sự phản chiếu. Tôi có nghĩa là bạn không thể chế nhạo nó trực tiếp bằng cách phân lớp nó và ghi đè các phương thức của nó.
Ellen Spertus

@espertus Tại sao không? Khi bạn khởi tạo đối tượng bạn đang kiểm tra, bạn có thể thay thế triển khai lớp con của singleton bất cứ nơi nào bạn đã sử dụng bản gốc. Vd:new ClazzToTest(mockSingleton);
Mike Rylander

Tôi chưa sử dụng Mockito, nhưng làm thế nào bạn có thể phân lớp một lớp có hàm tạo riêng, đó là trường hợp của singletons, ngoại trừ bằng cách sử dụng sự phản chiếu? Các cuộc thảo luận liên quan: stackoverflow.com/questions/2302179/mocking-a-singleton-class stackoverflow.com/questions/15939023/...
Ellen Spertus

23

Đây là một bài viết hay: http://javarevisited.blogspot.com.au/2013/03/difference-b between-singleton-potype-vs-static-class-java.html

Các lớp tĩnh

  • một lớp có tất cả các phương thức tĩnh .
  • hiệu suất tốt hơn (phương thức tĩnh được liên kết vào thời gian biên dịch)
  • không thể ghi đè phương thức, nhưng có thể sử dụng phương thức ẩn. ( Phương thức ẩn trong Java là gì? Ngay cả phần giải thích JavaDoc cũng khó hiểu )

    public class Animal {
        public static void foo() {
            System.out.println("Animal");
        }
    }
    
    public class Cat extends Animal {
        public static void foo() {  // hides Animal.foo()
            System.out.println("Cat");
        }
    }
    

Người độc thân

Tóm lại, tôi sẽ chỉ sử dụng các lớp tĩnh để giữ các phương thức sử dụng và sử dụng Singleton cho mọi thứ khác.


Chỉnh sửa


4
Tôi không biết về java, nhưng trong .Net, hai điểm cuối của bạn không chính xác. Các lớp tĩnh có thể tham chiếu các trường và các trường tĩnh, vì vậy trên trạng thái chúng bằng nhau. Và chúng được tải lười biếng - hàm tạo tĩnh được chạy khi: 1) Một thể hiện của lớp được tạo. 2) Bất kỳ thành viên tĩnh nào của lớp đều được tham chiếu. 1 không áp dụng, điều này để lại 2. Vì vậy, một lớp tĩnh không được tải cho đến khi nó được sử dụng lần đầu tiên.
jmoreno

1
Đối với lớp tĩnh, mặc dù bạn không thể ghi đè phương thức tĩnh, bạn có thể ẩn phương thức tĩnh khỏi cha mẹ của nó.
Max Peng

nếu Animal animal = new Cat();sau đó animal.foo();những gì xảy ra?
Shining_Dev

Lớp tĩnh @jmoreno không được tải cho đến lần đầu tiên sử dụng? Tôi tin rằng nó được lưu trữ trong bộ nhớ stack vào thời gian biên dịch. Và nó được truy cập ngay lập tức .. phải không?
Shining_Dev

@Lum_Dev: ít nhất là đối với .net, một lớp tĩnh có hàm tạo chạy khi truy cập lần đầu tiên, vì vậy không có nó không thể truy cập ngay lập tức. Về mặt lý thuyết, hàm tạo tĩnh có thể mất một lượng thời gian không giới hạn. Trường hợp nó (hoặc bất kỳ lớp nào khác được lưu trữ) là một chi tiết triển khai, điều đó không thực sự liên quan đến câu hỏi này.
jmoreno

22

Một ưu điểm khác của singleton là nó có thể dễ dàng được nối tiếp, điều này có thể cần thiết nếu bạn cần lưu trạng thái của nó vào đĩa hoặc gửi nó đi đâu đó từ xa.


19

Tôi không phải là một nhà lý thuyết OO tuyệt vời, nhưng từ những gì tôi biết, tôi nghĩ rằng tính năng OO duy nhất mà các lớp tĩnh thiếu so với Singletons là đa hình. Nhưng nếu bạn không cần nó, với một lớp tĩnh, tất nhiên bạn có thể có sự kế thừa (không chắc chắn về việc thực hiện giao diện) và đóng gói dữ liệu và chức năng.

Nhận xét của Morendil, "Phong cách thiết kế thể hiện trong một lớp tĩnh hoàn toàn là thủ tục" Tôi có thể sai, nhưng tôi không đồng ý. Trong các phương thức tĩnh, bạn có thể truy cập các thành viên tĩnh, sẽ giống hệt như các phương thức singleton truy cập các thành viên thể hiện đơn lẻ của chúng.

chỉnh sửa:
Bây giờ tôi thực sự nghĩ rằng một sự khác biệt khác là một lớp Tĩnh được khởi tạo ngay khi bắt đầu chương trình * và tồn tại trong suốt vòng đời của chương trình, trong khi một số đơn lẻ được thể hiện rõ ràng tại một số điểm và cũng có thể bị phá hủy.

* hoặc nó có thể được khởi tạo ngay lần đầu sử dụng, tùy thuộc vào ngôn ngữ, tôi nghĩ vậy.


15
Đúng, mọi người khác dường như bỏ qua thực tế là một lớp với các phương thức tĩnh cũng có thể có các trường tĩnh riêng mà nó vẫn có thể sử dụng để duy trì trạng thái (và hiển thị một số trong số chúng cho mã máy khách thông qua setters / getters tĩnh công khai).
dùng289463

17

Để minh họa quan điểm của Jon, những gì hiển thị bên dưới không thể được thực hiện nếu Logger là một lớp tĩnh. Lớp này SomeClassmong muốn một thể hiện củaILogger hiện thực hiện được truyền vào hàm tạo của nó.

Lớp đơn là quan trọng để tiêm phụ thuộc là có thể.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {

            var someClass = new SomeClass(Logger.GetLogger());
        }


    }

    public class SomeClass 
    {
        public SomeClass(ILogger MyLogger)
        {

        }
    }

    public class Logger : ILogger
    {
        private static Logger _logger;
        private Logger() { }

        public static Logger GetLogger()
        {
            if (_logger==null)
            {
                _logger = new Logger();
            }

            return _logger;
        }

        public void Log()
        {

        }

    }


    public interface ILogger
    {
         void Log();
    }
}

13

Vâng, một singleton chỉ là một lớp bình thường được khởi tạo nhưng chỉ một lần và gián tiếp từ mã máy khách. Lớp tĩnh không được khởi tạo. Theo tôi biết các phương thức tĩnh (lớp tĩnh phải có phương thức tĩnh) nhanh hơn phương thức không tĩnh.

Chỉnh sửa:
FxCop Mô tả quy tắc hiệu suất: "Các phương thức không truy cập dữ liệu cá thể hoặc phương thức gọi cuộc gọi có thể được đánh dấu là tĩnh (Được chia sẻ trong VB). Sau khi làm như vậy, trình biên dịch sẽ phát ra các trang web cuộc gọi không ảo đến các thành viên này sẽ ngăn chặn kiểm tra trong thời gian chạy cho mỗi cuộc gọi đảm bảo con trỏ đối tượng hiện tại là không null. Điều này có thể dẫn đến mức tăng hiệu suất có thể đo được đối với mã nhạy cảm hiệu năng. Trong một số trường hợp, việc không truy cập vào đối tượng hiện tại thể hiện vấn đề chính xác. "
Tôi thực sự không biết nếu điều này cũng áp dụng cho các phương thức tĩnh trong các lớp tĩnh.


11

Singleton được khởi tạo, nó chỉ có một trường hợp duy nhất được khởi tạo, do đó là một trong Singleton.

Một lớp tĩnh không thể được khởi tạo bởi bất cứ thứ gì khác ngoài chính nó.


Lớp tĩnh có thể được khởi tạo rất nhiều trong java. Đọc docs.oracle.com/javase/tutorial/java/javaOO/nested.html. Đồng thời tham khảo câu trả lời của tôi stackoverflow.com/a/37114702/1406510
nanosoft

8

Sự khác biệt chính là:

  • Singleton có một cá thể / đối tượng trong khi lớp tĩnh là một nhóm các phương thức tĩnh
  • Singleton có thể được mở rộng, ví dụ thông qua một giao diện trong khi lớp tĩnh không thể.
  • Singleton có thể được kế thừa, hỗ trợ các nguyên tắc mở / đóng trong các nguyên tắc RẮN, mặt khác, lớp tĩnh không thể được kế thừa và chúng ta cần phải tự thay đổi.
  • Đối tượng Singleton có thể được truyền cho các phương thức trong khi lớp tĩnh vì nó không có thể hiện được như là tham số

7

Singleton là cách tiếp cận tốt hơn từ quan điểm thử nghiệm. Không giống như các lớp tĩnh, singleton có thể thực hiện các giao diện và bạn có thể sử dụng thể hiện giả và tiêm chúng.

Trong ví dụ dưới đây tôi sẽ minh họa điều này. Giả sử bạn có một phương thức is Goodprice () sử dụng phương thức getprice () và bạn triển khai getprice () làm phương thức trong một singleton.

singleton cung cấp chức năng getprice:

public class SupportedVersionSingelton {

    private static ICalculator instance = null;

    private SupportedVersionSingelton(){

    }

    public static ICalculator getInstance(){
        if(instance == null){
            instance = new SupportedVersionSingelton();
        }

        return instance;
    }

    @Override
    public int getPrice() {
        // calculate price logic here
        return 0;
    }
}

Sử dụng getprice:

public class Advisor {

    public boolean isGoodDeal(){

        boolean isGoodDeal = false;
        ICalculator supportedVersion = SupportedVersionSingelton.getInstance();
        int price = supportedVersion.getPrice();

        // logic to determine if price is a good deal.
        if(price < 5){
            isGoodDeal = true;
        }

        return isGoodDeal;
    }
}


In case you would like to test the method isGoodPrice , with mocking the getPrice() method you could do it by:
Make your singleton implement an interface and inject it. 



  public interface ICalculator {
        int getPrice();
    }

Thực hiện Singleton cuối cùng:

public class SupportedVersionSingelton implements ICalculator {

    private static ICalculator instance = null;

    private SupportedVersionSingelton(){

    }

    public static ICalculator getInstance(){
        if(instance == null){
            instance = new SupportedVersionSingelton();
        }

        return instance;
    }

    @Override
    public int getPrice() {
        return 0;
    }

    // for testing purpose
    public static void setInstance(ICalculator mockObject){
        if(instance != null ){
instance = mockObject;
    }

lớp kiểm tra:

public class TestCalculation {

    class SupportedVersionDouble implements ICalculator{
        @Override
        public int getPrice() { 
            return 1;
        }   
    }
    @Before
    public void setUp() throws Exception {
        ICalculator supportedVersionDouble = new SupportedVersionDouble();
        SupportedVersionSingelton.setInstance(supportedVersionDouble);

    }

    @Test
    public void test() {
          Advisor advidor = new Advisor();
          boolean isGoodDeal = advidor.isGoodDeal();
          Assert.assertEquals(isGoodDeal, true);

    }

}

Trong trường hợp chúng tôi sử dụng phương pháp thay thế bằng cách sử dụng phương thức tĩnh để triển khai getprice (), rất khó để giả định getprice (). Bạn có thể giả lập tĩnh với mock điện, nhưng không phải tất cả các sản phẩm đều có thể sử dụng nó.


1
Điều đó bây giờ không phải là luồng an toàn và nói chung là khó chịu về cách bạn truy cập vào việc thực hiện giao diện. Chắc chắn, có một giao diện là tốt cho khả năng kiểm tra - nhưng sau đó tại sao phải bận tâm với một singleton? Chỉ cần tránh có một singleton ở tất cả; có một lớp thực hiện nó cho mục đích sản xuất, một lớp thực hiện cho mục đích thử nghiệm và đưa ra ví dụ phù hợp tùy thuộc vào những gì bạn đang làm. Không cần phải ghép đôi singleton với người gọi của nó cả.
Jon Skeet

Cảm ơn vì bạn đã phản hồi. nó rất đơn giản để làm cho nó an toàn. Ngoài ra, tôi sử dụng singleton cho mục đích lưu trữ.
Amir Bareket

1
Vâng, mặc dù với chi phí vô nghĩa. Một lần nữa, thật đơn giản để không sử dụng singleton.
Jon Skeet

6

Tôi đồng ý với định nghĩa này:

Từ " độc thân " có nghĩa là một đối tượng trong suốt vòng đời ứng dụng, vì vậy phạm vi nằm ở cấp ứng dụng.

các tĩnh không có bất kỳ con trỏ đối tượng, vì vậy phạm vi đang ở mức App Domain.

Hơn nữa cả hai nên được thực hiện để được an toàn chủ đề.

Bạn có thể tìm thấy những khác biệt thú vị khác về: Singleton Pattern Versus static Class


5

Một sự khác biệt đáng chú ý là sự khác biệt ngay lập tức đi kèm với Singletons.

Với các lớp tĩnh, nó được tạo bởi CLR và chúng tôi không kiểm soát nó. với singletons, đối tượng được khởi tạo ngay trong trường hợp đầu tiên mà nó đã cố gắng truy cập.


4

Trong nhiều trường hợp, hai cái này không có sự khác biệt thực tế, đặc biệt là nếu cá thể singleton không bao giờ thay đổi hoặc thay đổi rất chậm, ví dụ như giữ cấu hình.

Tôi muốn nói rằng sự khác biệt lớn nhất là một singleton vẫn là một Java Bean bình thường, trái ngược với một lớp Java chỉ tĩnh chuyên biệt. Và vì điều này, một người độc thân được chấp nhận trong nhiều tình huống hơn; thực tế nó là chiến lược khởi tạo mặc định của Spring Framework. Người tiêu dùng có thể hoặc không thể biết đó là một người độc thân được thông qua, họ chỉ coi nó như một hạt đậu Java bình thường. Nếu yêu cầu thay đổi và một singleton cần phải trở thành một nguyên mẫu thay vào đó, như chúng ta thường thấy trong Spring, nó có thể được thực hiện hoàn toàn liền mạch mà không cần một dòng mã thay đổi cho người tiêu dùng.

Một số người khác đã đề cập trước đó rằng một lớp tĩnh nên hoàn toàn theo thủ tục, ví dụ java.lang.Math. Trong tâm trí của tôi, một lớp như vậy không bao giờ nên được thông qua và chúng không bao giờ nên giữ bất cứ thứ gì ngoài cuối cùng tĩnh làm thuộc tính. Đối với mọi thứ khác, hãy sử dụng một singleton vì nó linh hoạt hơn và dễ bảo trì hơn.


4

Chúng tôi có khung DB của chúng tôi giúp kết nối tới Back end. Để tránh việc đọc bẩn trên nhiều người dùng, chúng tôi đã sử dụng mẫu singleton để đảm bảo chúng tôi có một phiên bản duy nhất có sẵn tại bất kỳ thời điểm nào.

Trong c #, một lớp tĩnh không thể thực hiện giao diện. Khi một lớp cá thể duy nhất cần triển khai giao diện cho các hợp đồng kinh doanh hoặc mục đích IoC, đây là nơi tôi sử dụng mẫu Singleton mà không có lớp tĩnh

Singleton cung cấp một cách để duy trì trạng thái trong các tình huống không trạng thái

Mong rằng sẽ giúp bạn ..


3
  1. Tải lười biếng
  2. Hỗ trợ các giao diện, để thực hiện riêng biệt có thể được cung cấp
  3. Khả năng trả về loại dẫn xuất (dưới dạng kết hợp giữa tải và tải xuống giao diện)

Lớp tĩnh lồng nhau có thể thực hiện rất nhiều giao diện trong java. Điểm thứ hai của bạn là sai.
nanosoft

3

a. Tuần tự hóa - Các thành viên tĩnh thuộc về lớp và do đó không thể được tuần tự hóa.

b. Mặc dù chúng ta đã đặt hàm tạo riêng tư, các biến thành viên tĩnh vẫn sẽ được chuyển đến lớp con.

c. Chúng ta không thể lười khởi tạo vì mọi thứ sẽ chỉ được tải khi tải lớp.


3

Từ góc độ máy khách, hành vi tĩnh được biết đến với máy khách nhưng hành vi Singleton có thể được hoàn thành ẩn khỏi máy khách. Khách hàng có thể không bao giờ biết rằng chỉ có một trường hợp duy nhất anh ta chơi đi chơi lại.


3

Tôi đọc những điều sau đây và nghĩ rằng nó cũng có ý nghĩa:

Chăm sóc doanh nghiệp

Hãy nhớ rằng, một trong những quy tắc OO quan trọng nhất là một đối tượng tự chịu trách nhiệm. Điều này có nghĩa là các vấn đề liên quan đến vòng đời của một lớp nên được xử lý trong lớp, không được ủy quyền cho các cấu trúc ngôn ngữ như tĩnh, v.v.

từ cuốn sách Quy trình tư duy hướng đối tượng 4th Ed.


Tôi sẽ không đồng ý, vì điều này thực sự chỉ bổ sung một trách nhiệm cho lớp, điều này (giả sử nó làm bất cứ điều gì) có nghĩa là bây giờ nó vi phạm Nguyên tắc Trách nhiệm duy nhất.
thợ rèn

3

Trong một bài viết tôi đã viết, tôi đã mô tả quan điểm của mình về lý do tại sao singleton tốt hơn nhiều so với một lớp tĩnh:

  1. Lớp tĩnh không thực sự là lớp chuẩn - đó là một không gian tên với các hàm và biến
  2. Sử dụng lớp tĩnh không phải là một cách thực hành tốt vì phá vỡ các nguyên tắc lập trình hướng đối tượng
  3. Lớp tĩnh không thể được truyền làm tham số cho khác
  4. Lớp tĩnh không phù hợp với khởi tạo lười biếng
  5. Khởi tạo và sử dụng lớp tĩnh luôn khó theo dõi
  6. Thực hiện quản lý luồng là khó

Tôi sẽ viết nó cho ngữ pháp tiếng Anh, nhưng nếu không, nó là một bài đọc thú vị :)
Noctis

3
  1. Chúng ta có thể tạo đối tượng của lớp singleton và truyền nó cho phương thức.

  2. Lớp Singleton không hạn chế quyền thừa kế.

  3. Chúng ta không thể loại bỏ các đối tượng của một lớp tĩnh nhưng có thể là lớp đơn.


Việc sử dụng chuyển một singleton vào một phương thức là gì nếu luôn luôn chỉ có một và một luôn luôn có một tham chiếu tĩnh?
Aaron Franke

3

Phân biệt với lớp tĩnh

JDK có các ví dụ về cả singleton và static, một mặt java.lang.Mathlà lớp cuối cùng với các phương thức tĩnh, mặt khác java.lang.Runtimelà lớp singleton.

Ưu điểm của singleton

  • Nếu nhu cầu duy trì trạng thái của bạn so với mẫu đơn là lựa chọn tốt hơn lớp tĩnh, bởi vì duy trì trạng thái trong lớp tĩnh dẫn đến lỗi, đặc biệt là trong môi trường đồng thời, điều đó có thể dẫn đến điều kiện chạy đua mà không sửa đổi song song đầy đủ bởi nhiều luồng.

  • Lớp Singleton có thể được tải lười biếng nếu nó là một vật nặng, nhưng lớp tĩnh không có lợi thế như vậy và luôn được tải một cách háo hức.

  • Với singleton, bạn có thể sử dụng tính kế thừa và đa hình để mở rộng lớp cơ sở, triển khai giao diện và cung cấp các cài đặt khác nhau.

  • Do các phương thức tĩnh trong Java không thể bị ghi đè, nên chúng dẫn đến tính không linh hoạt. Mặt khác, bạn có thể ghi đè các phương thức được xác định trong lớp singleton bằng cách mở rộng nó.

Nhược điểm của lớp tĩnh

  • Viết bài kiểm tra đơn vị cho singleton dễ hơn so với lớp tĩnh, bởi vì bạn có thể vượt qua đối tượng giả bất cứ khi nào singleton được mong đợi.

Ưu điểm của lớp tĩnh

  • Lớp tĩnh cung cấp hiệu năng tốt hơn singleton, bởi vì các phương thức tĩnh được liên kết theo thời gian biên dịch.

Có một số nhận thức về mẫu singleton mỗi cái có ưu điểm và nhược điểm.

  • Háo hức tải đơn
  • Kiểm tra khóa đơn
  • Thành ngữ chủ sở hữu khởi tạo theo yêu cầu
  • Đơn vị dựa trên enum

Mô tả chi tiết mỗi bài trong số chúng quá dài dòng nên tôi chỉ cần đặt một liên kết đến một bài viết hay - Tất cả những gì bạn muốn biết về Singleton


2

Có một sự khác biệt rất lớn giữa một thể hiện của lớp tĩnh đơn (nghĩa là một thể hiện của một lớp, đó là một biến tĩnh hoặc biến toàn cục) và một con trỏ tĩnh đơn đối với một thể hiện của lớp trên heap:

Khi ứng dụng của bạn thoát, hàm hủy của thể hiện của lớp tĩnh sẽ được gọi. Điều đó có nghĩa là nếu bạn đã sử dụng thể hiện tĩnh đó như một singleton, thì singleton của bạn đã ngừng hoạt động bình thường. Nếu vẫn còn mã đang chạy sử dụng singleton đó, ví dụ trong một luồng khác, mã đó có khả năng bị sập.


1
Vậy nếu thoát ứng dụng thì Singleton có còn trong bộ nhớ không?
nanosoft

Tôi nghĩ bạn có nghĩa là khi chủ đề hiện tại của bạn thoát, không phải ứng dụng, phải không? Nếu ứng dụng thoát, không có cách nào để một luồng khác sử dụng bất cứ thứ gì từ nó.
Tom Brito

2

Sự khác biệt trong đầu tôi là triển khai lập trình hướng đối tượng (Singleton / Prototype) hoặc lập trình chức năng (Tĩnh).

Chúng ta quá tập trung vào số lượng đối tượng được tạo bởi mẫu đơn khi điều chúng ta nên tập trung vào là cuối cùng chúng ta giữ một đối tượng. Giống như những người khác đã nói, nó có thể được mở rộng, thông qua như một tham số nhưng quan trọng nhất là nó có đầy đủ trạng thái.

Mặt khác, tĩnh được sử dụng để thực hiện lập trình chức năng. Các thành viên tĩnh thuộc về một lớp. Họ không quốc tịch.

Nhân tiện, bạn đã biết rằng bạn có thể tạo các lớp tĩnh singleton :)


Điểm của việc truyền một singleton như là một tham số vì nó luôn có một tham chiếu tĩnh trên lớp là gì?
Aaron Franke
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.