2008-09-05 29 views
82

Đặt các cân nhắc thiết kế khi quyết định sử dụng singleton so với lớp tĩnh. Khi làm điều này, bạn buộc phải đối chiếu với cả hai, vì vậy bất kỳ sự tương phản nào bạn có thể đưa ra cũng hữu ích trong việc thể hiện quá trình suy nghĩ của bạn! Ngoài ra, mọi người phỏng vấn đều thích xem các ví dụ minh họa. :)Khi nào bạn nên sử dụng mẫu đơn thay vì một lớp tĩnh?

+0

một lớp java không thể thực hiện tĩnh trừ khi một lớp bên trong là – Harshana

+1

Nếu trạng thái của đối tượng không thành vấn đề, sau đó sử dụng singleton, nếu không, hãy sử dụng lớp tĩnh. –

Trả lời

79
  • Người dùng có thể triển khai giao diện và kế thừa từ các lớp khác.
  • Người dùng có thể bị tải lười biếng. Chỉ khi nó thực sự là cần thiết. Điều đó rất tiện lợi nếu khởi tạo bao gồm các kết nối cơ sở dữ liệu hoặc tải tải đắt tiền.
  • Singletons cung cấp một đối tượng thực tế.
  • Có thể mở rộng một số đơn vị thành một nhà máy. Việc quản lý đối tượng đằng sau hậu trường là trừu tượng để nó có thể duy trì tốt hơn và dẫn đến mã tốt hơn.
+2

Hãy xem liên kết này cũng: http://codeofdoom.com/wordpress/2008/04/20/Làm thế nào-và-khi-to-sử dụng-singleton-classes/ – Amit

+4

"Singletons có thể được tải lười biếng ed "- trong C#, hàm tạo tĩnh chỉ được gọi là lần đầu tiên một thành viên tĩnh được tham chiếu. Trong PHP, bạn có thể sử dụng tính năng tự động tải để chỉ chạy nó lần đầu tiên lớp được sử dụng. – mpen

+0

Java khởi tạo tĩnh cũng lười. Không có điểm cho Singletons ở đó. – MikeFHay

-1

Khi lớp đơn cần trạng thái. Singletons duy trì một trạng thái toàn cầu, các lớp tĩnh không.

Ví dụ, làm cho một helper xung quanh một lớp học đăng ký: Nếu bạn có hive changable (HKEY Current User vs HKEY máy địa phương), bạn có thể đi:

RegistryEditor editor = RegistryEditor.GetInstance(); 
editor.Hive = LocalMachine 

Bây giờ bất kỳ cuộc gọi hơn nữa để singleton mà sẽ hoạt động trên tổ máy địa phương. Nếu không, bằng cách sử dụng một lớp tĩnh, bạn sẽ phải chỉ định rằng Local Machine hive everytiem, hoặc có một phương thức như ReadSubkeyFromLocalMachine.

+1

Tôi sẽ tranh luận chống lại việc sử dụng Singleton theo cách này ... Rất nguy hiểm khi giữ cho các trạng thái kéo dài, bởi vì người gọi tiếp theo có thể quên đặt tổ ong và ghi vào sổ đăng ký trong tổ hợp sai ... :-(Điều này – nus

8

Tôi cho rằng sự khác biệt duy nhất là cú pháp: MySingleton.Current.Whatever() so với MySingleton.Whatever(). Nhà nước, như David đã đề cập, cuối cùng là "tĩnh" trong cả hai trường hợp.


EDIT: Các chôn lữ đoàn đến hơn từ digg ... dù sao đi nữa, tôi nghĩ đến một trường hợp đó sẽ đòi hỏi một singleton. Các lớp tĩnh không thể kế thừa từ một lớp cơ sở cũng như không triển khai thực hiện một giao diện (ít nhất là trong .Net chúng không thể). Vì vậy, nếu bạn yêu cầu chức năng này thì bạn phải sử dụng một singleton.

2

Nếu theo "lớp tĩnh" nghĩa là lớp chỉ có các biến tĩnh, thì chúng thực sự có thể duy trì trạng thái. Sự hiểu biết của tôi là sự khác biệt duy nhất sẽ là cách bạn tiếp cận điều này. Ví dụ:

MySingleton().getInstance().doSomething(); 

so

MySingleton.doSomething(); 

Các bên trong của MySingleton rõ ràng sẽ khác nhau giữa chúng nhưng, vấn đề thread-an toàn sang một bên, cả hai đều sẽ biểu diễn cùng với liên quan đến các mã khách hàng.

+2

Singletons là bản thân các đối tượng -> chúng có thể được chuyển thành các đối số –

1

Không bao giờ được sử dụng Singletons (trừ khi bạn xem xét một lớp không có trạng thái có thể thay đổi một singleton). "các lớp tĩnh" sẽ không có trạng thái có thể thay đổi, ngoại trừ các bộ nhớ cache an toàn có thể là chủ đề và các loại tương tự.

Khá nhiều ví dụ về singleton cho thấy cách không thực hiện.

+3

Còn các lớp quản lý kiểm soát các tài nguyên phần cứng thì sao? Còn các lớp tệp nhật ký thì sao? – RJFalconer

0

Nếu singleton là thứ bạn có thể vứt bỏ, để dọn dẹp sau đó, bạn có thể xem xét nó khi nó là một nguồn tài nguyên hạn chế (ví dụ: chỉ 1 trong số đó) mà bạn không cần mọi lúc, và có một số loại bộ nhớ hoặc chi phí tài nguyên khi nó được phân bổ.

Mã dọn dẹp trông tự nhiên hơn khi bạn có một singleton, trái ngược với một lớp tĩnh chứa các trường trạng thái tĩnh.

Mã này, tuy nhiên, sẽ trông giống như một trong hai cách vì vậy nếu bạn có lý do cụ thể hơn để hỏi, có lẽ bạn nên xây dựng.

0

Cả hai có thể khá giống nhau, nhưng hãy nhớ rằng Singleton thực phải tự chính nó được khởi tạo (cấp, một lần) và sau đó được phân phát.Một lớp cơ sở dữ liệu PHP trả về một thể hiện của mysqli không thực sự là một Singleton (như một số người gọi nó), bởi vì nó trả về một thể hiện của một lớp khác, không phải là một cá thể của lớp có cá thể như một thành viên tĩnh.

Vì vậy, nếu bạn đang viết một lớp mới mà bạn dự định chỉ cho phép một phiên bản trong mã của bạn, bạn cũng có thể viết nó dưới dạng Singleton. Hãy nghĩ về nó như viết một lớp đơn giản và thêm vào nó để tạo điều kiện cho yêu cầu đơn giản hóa. Nếu bạn đang sử dụng lớp của người khác mà bạn không thể sửa đổi (như mysqli), bạn nên sử dụng một lớp tĩnh (ngay cả khi bạn không đặt tiền tố cho định nghĩa của từ khóa đó).

0

Singletons linh hoạt hơn, có thể hữu ích trong trường hợp bạn muốn phương thức Instance trả về các lớp con cụ thể khác nhau của kiểu Singleton dựa trên một số ngữ cảnh.

0

Không thể chuyển các lớp tĩnh làm đối số; trường hợp của một singleton có thể được. Như đã đề cập trong các câu trả lời khác, hãy xem các vấn đề về luồng với các lớp tĩnh.

rp

0

Một singleton có thể có hàm tạo và hàm hủy. Tùy thuộc vào ngôn ngữ của bạn, nhà xây dựng có thể được gọi tự động trong lần đầu tiên singleton của bạn được sử dụng, hoặc không bao giờ nếu singleton của bạn không được sử dụng ở tất cả. Một lớp tĩnh sẽ không có khởi tạo tự động như vậy.

Sau khi tham chiếu đến một đối tượng đơn lẻ thu được, nó có thể được sử dụng giống như bất kỳ đối tượng nào khác. Mã khách hàng thậm chí có thể không cần phải biết sử dụng nó một singleton nếu một tham chiếu đến singleton được lưu trữ trước đây về:

Foo foo = Foo.getInstance(); 
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton 

Điều này rõ ràng làm cho mọi thứ dễ dàng hơn khi bạn chọn mương mẫu Singleton trong lợi của một mô hình thực , như IoC.

0

Sử dụng mẫu đơn khi bạn cần tính toán thứ gì đó trong thời gian chạy mà bạn sẽ tính toán tại thời gian biên dịch nếu bạn có thể, như bảng tra cứu.

4

Hãy suy nghĩ về một singleton như một dịch vụ. Đó là một đối tượng cung cấp một bộ chức năng cụ thể. Ví dụ.

ObjectFactory.getInstance().makeObject(); 

Nhà máy đối tượng là đối tượng thực hiện dịch vụ cụ thể.

Ngược lại, một lớp đầy đủ các phương pháp tĩnh là tập hợp các hành động mà bạn có thể muốn thực hiện, được sắp xếp trong một nhóm liên quan (Lớp học). Ví dụ.

StringUtils.reverseString("Hello"); 
StringUtils.concat("Hello", "World"); 

Ví dụ về StringUtils đây là tập hợp các chức năng có thể áp dụng ở mọi nơi. Các đối tượng nhà máy singleton là một loại đối tượng cụ thể với một trách nhiệm rõ ràng có thể được tạo ra và thông qua xung quanh nơi cần thiết.

7

Một trong những cuộc thảo luận yêu thích của tôi về vấn đề này là here (trang web gốc xuống, hiện được liên kết với Internet Archive Wayback Machine.)

Để tóm tắt những lợi thế linh hoạt của một Singleton:

  • một Singleton có thể dễ dàng chuyển đổi vào một nhà máy
  • một Singleton có thể dễ dàng sửa đổi để trở khác nhau lớp con
  • này có thể dẫn đến một ứng dụng dễ bảo trì hơn
4

Lớp tĩnh là khởi tạo d khi chạy. Điều này có thể tốn thời gian. Singletons có thể được instantiated chỉ khi cần thiết.

+12

Các trình đơn được khởi tạo trong thời gian chạy quá ... – recursive

+0

@recursive: Singleton instantiation có thể được kiểm soát –

+3

có lẽ một từ tốt hơn sẽ được khởi tạo (chứ không phải là instantiation) – Marlon

0

Tôi nghĩ một nơi mà Singleton sẽ có ý nghĩa hơn lớp tĩnh là khi bạn phải xây dựng một nhóm tài nguyên tốn kém (như kết nối cơ sở dữ liệu). Bạn sẽ không quan tâm đến việc tạo nhóm nếu không có ai sử dụng chúng (lớp tĩnh sẽ có nghĩa là bạn thực hiện công việc tốn kém khi lớp được nạp).

5

Một lớp tĩnh có tải trọng biến tĩnh là một chút hack.

/** 
* Grotty static semaphore 
**/ 
public static class Ugly { 

    private static int count; 

    public synchronized static void increment(){ 
     count++; 
    } 

    public synchronized static void decrement(){ 
     count--; 
     if(count<0) { 
      count=0; 
     } 
    } 

    public synchronized static boolean isClear(){ 
     return count==0;  

    } 
    } 

Một singleton có thực tế tốt hơn.

/** 
* Grotty static semaphore 
**/ 
public static class LessUgly { 
    private static LessUgly instance; 

    private int count; 

    private LessUgly(){ 
    } 

    public static synchronized getInstance(){ 
    if(instance==null){ 
     instance = new LessUgly(); 
    } 
    return instance; 
    } 
    public synchronized void increment(){ 
     count++; 
    } 

    public synchronized void decrement(){ 
     count--; 
     if(count<0) { 
      count=0; 
     } 
    } 

    public synchronized boolean isClear(){ 
     return count==0;  

    } 
    } 

Trạng thái CHỈ trong trường hợp.

Vì vậy, các singleton có thể được sửa đổi sau này để làm tổng hợp, trường hợp thread-local vv Và không có mã đã viết cần phải thay đổi để có được lợi ích.

public static class LessUgly { 
     private static Hashtable<String,LessUgly> session; 
     private static FIFO<LessUgly> freePool = new FIFO<LessUgly>(); 
     private static final POOL_SIZE=5; 
     private int count; 

     private LessUgly(){ 
     } 

     public static synchronized getInstance(){ 
     if(session==null){ 
      session = new Hashtable<String,LessUgly>(POOL_SIZE); 
      for(int i=0; i < POOL_SIZE; i++){ 
       LessUgly instance = new LessUgly(); 
       freePool.add(instance) 
      } 
     } 
     LessUgly instance = session.get(Session.getSessionID()); 
     if(instance == null){ 
      instance = freePool.read(); 
     } 
     if(instance==null){ 
      // TODO search sessions for expired ones. Return spares to the freePool. 
      //FIXME took too long to write example in blog editor. 
     } 
     return instance; 
     }  

Có thể làm điều gì đó tương tự với lớp tĩnh nhưng sẽ có phí trên mỗi cuộc gọi trong công văn gián tiếp.

Bạn có thể nhận được cá thể và chuyển nó tới một hàm làm đối số. Điều này cho phép mã được chuyển đến singleton "đúng". Chúng tôi biết bạn sẽ chỉ cần một trong số đó ... cho đến khi bạn không.

Lợi ích lớn là các trình đơn trạng thái có thể được tạo thành an toàn, trong khi một lớp tĩnh không thể, trừ khi bạn sửa đổi nó thành một singleton bí mật.

4

Không được sử dụng đơn lẻ theo cách giống như lớp tĩnh.Trong essense,

MyStaticClass.GetInstance().DoSomething(); 

là cơ bản giống như

MyStaticClass.DoSomething(); 

gì bạn thực sự cần phải làm là điều trị các singleton như chỉ là một đối tượng. Nếu một dịch vụ đòi hỏi một thể hiện của kiểu singleton, sau đó vượt qua dụ rằng trong constructor:

var svc = new MyComplexServce(MyStaticClass.GetInstance()); 

Dịch vụ này không nên biết rằng đối tượng là một singleton, và phải đối xử với các đối tượng như chỉ là một đối tượng.

Đối tượng chắc chắn có thể được triển khai, dưới dạng chi tiết triển khai và như một khía cạnh của cấu hình tổng thể, dưới dạng singleton nếu điều đó giúp mọi thứ trở nên dễ dàng hơn. Nhưng những thứ sử dụng đối tượng không cần phải biết liệu đối tượng đó có phải là đơn hay không.

0

Một singleton cũng là một ý tưởng hay nếu bạn muốn buộc bộ nhớ đệm dữ liệu hiệu quả. ví dụ, tôi có một lớp tìm kiếm các định nghĩa trong một tài liệu xml. Vì việc phân tích cú pháp tài liệu có thể mất một lúc, tôi thiết lập một bộ nhớ đệm của các định nghĩa (tôi sử dụng SoftReferences để tránh outOfmemeoryErrors). Nếu định nghĩa mong muốn không có trong bộ đệm, tôi sẽ phân tích cú pháp xml đắt tiền. Nếu không, tôi sẽ trả lại một bản sao từ bộ nhớ cache. Vì có nhiều bộ nhớ cache có nghĩa là tôi vẫn có thể tải cùng một định nghĩa nhiều lần, tôi cần phải có bộ nhớ cache tĩnh. Tôi chọn để thực hiện lớp này như là một singleton để tôi có thể viết lớp chỉ sử dụng các thành viên dữ liệu bình thường (không tĩnh). Điều này cho phép tôi vẫn tạo ra một istantiation của lớp tôi cần nó vì một số lý do (serialization, đơn vị thử nghiệm, vv)

13

Làm thế nào về "tránh cả hai"? Độc thân và các lớp học tĩnh:

  • có thể giới thiệu tình trạng toàn cầu
  • Nhận kết chặt chẽ với nhiều lớp khác
  • Ẩn phụ thuộc
  • có thể làm cho các lớp kiểm tra đơn vị trong sự cô lập khó

Thay vào đó, hãy nhìn vào các thư viện Dependency InjectionInversion of Control Container. Một số thư viện IoC sẽ xử lý quản lý suốt đời cho bạn.

(Như mọi khi, có những ngoại lệ, chẳng hạn như các lớp học toán tĩnh và phương pháp # mở rộng C.)

+1

Nhỏ nits: singleton lớp học tương thích với các kỹ thuật tiêm phụ thuộc (chỉ cần tiêm chúng vào các lớp phụ thuộc của họ và họ không cần phải mã hóa cứng bất cứ điều gì) - điều này cho phép chế nhạo và thử nghiệm trong sự cô lập. Chúng cũng là một mẫu thiết kế hợp lệ để quản lý các tài nguyên được biết đến là nền tảng hạn chế. (Ví dụ cổ điển là các máy in không có quản lý tranh chấp.) – cdleary

+0

@cdleary - đã đồng ý; tuy nhiên việc thực hiện cổ điển thường để lại Singleton.getInstance() trong toàn bộ codebase. "Singletons" để quản lý tài nguyên, cache, v.v. có thể được thực hiện với các khung công tác POCOs/POJO và IoC Container hỗ trợ quản lý suốt đời (đăng ký kiểu tồn tại của container và mọi độ phân giải sẽ nhận được cùng một cá thể). – TrueWill

+9

Nếu bạn muốn cung cấp cho Singletons một nơi chôn cất thích hợp, hãy truy cập http://www.singletonfuneralservice.com/ – TrueWill

2

Singleton pattern thường được sử dụng để phục vụ dụ dữ liệu độc lập hoặc tĩnh nơi nhiều luồng có thể truy cập dữ liệu cùng lúc. Một ví dụ có thể là các mã trạng thái.

0

Singleton giống như một dịch vụ, như đã đề cập. Pro là sự linh hoạt của nó. Tĩnh, tốt, bạn cần một số phần tĩnh để thực hiện Singleton.

Singleton có mã để xử lý việc khởi tạo đối tượng thực sự thứ, đó có thể là trợ giúp tuyệt vời nếu bạn gặp phải vấn đề về đua xe. Trong một giải pháp tĩnh, bạn có thể cần phải đối phó với các vấn đề đua xe tại nhiều vị trí mã.

Tuy nhiên, giống như Singleton có thể được xây dựng với một số biến tĩnh, bạn có thể so sánh nó với 'goto'. Nó có thể rất hữu ích cho việc xây dựng các cấu trúc khác, nhưng bạn thực sự cần phải biết cách sử dụng nó và không nên 'lạm dụng' nó.Do đó khuyến nghị chung là để dính vào Singleton, và sử dụng tĩnh nếu bạn có.

cũng kiểm tra các bài khác: Why choose a static class over a singleton implementation?

0

tham khảo this

Tóm lại:

a. Một nguyên tắc dễ dàng mà bạn có thể làm theo là nếu nó không cần phải duy trì trạng thái, bạn có thể sử dụng lớp tĩnh, nếu không bạn nên sử dụng Singleton.

b. sử dụng Singleton là nếu nó là một đối tượng đặc biệt “nặng”. Nếu đối tượng của bạn là lớn và chiếm một số lượng hợp lý của bộ nhớ, rất nhiều n/w cuộc gọi (kết nối hồ bơi) .. etc. Để đảm bảo rằng nó sẽ không được khởi tạo nhiều lần. Một lớp Singleton sẽ giúp ngăn chặn trường hợp như vậy xảy ra

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