2010-04-19 38 views
11

Tôi cần phải lưu trữ một loạt các biến cần phải được truy cập trên toàn cầu và tôi tự hỏi nếu một mẫu đơn sẽ được áp dụng. Từ những ví dụ tôi đã thấy, một mẫu đơn giản chỉ là một lớp tĩnh mà không thể kế thừa được. Nhưng những ví dụ tôi đã thấy quá phức tạp cho nhu cầu của tôi. Điều gì sẽ là lớp singleton đơn giản nhất? Tôi có thể tạo một lớp tĩnh, kín với một số biến bên trong không?Mẫu Singleton cho C#

Trả lời

30

Thông thường một singleton không phải là một lớp tĩnh - một singleton sẽ cung cấp cho bạn một trường hợp duy nhất của một lớp học.

Tôi không biết những gì ví dụ bạn đã nhìn thấy, nhưng thường là singleton pattern có thể được thực sự đơn giản trong C#:

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 
    static Singleton() {} // Make sure it's truly lazy 
    private Singleton() {} // Prevent instantiation outside 

    public static Singleton Instance { get { return instance; } } 
} 

Đó không phải là khó khăn.

Lợi thế của một singleton trên các thành viên tĩnh là lớp có thể thực hiện các giao diện vv Đôi khi điều đó hữu ích - nhưng lần khác, các thành viên tĩnh sẽ thực sự làm tốt. Ngoài ra, nó thường dễ dàng hơn để di chuyển từ một singleton sang một singleton không muộn hơn, ví dụ: truyền vào singleton như một đối tượng "cấu hình" cho các lớp phụ thuộc, thay vì các lớp phụ thuộc đó thực hiện các cuộc gọi tĩnh trực tiếp.

Cá nhân tôi cố gắng tránh sử dụng những người độc thân khi có thể - họ làm cho thử nghiệm khó hơn, ngoài bất cứ thứ gì khác. Họ đôi khi có thể hữu ích mặc dù.

+0

Giải thích tuyệt vời .... Bạn có thể cho chúng tôi biết một ví dụ (thời gian thực), nơi bạn có thể tìm thấy mẫu đơn giản hữu ích không? +1 – Raja

+0

@Raja: Tôi không thể nghĩ ra bất kỳ tình huống thực sự nào vào lúc này, mặc dù điều đó không có nghĩa là tôi chưa từng sử dụng. –

+0

@Raja đây là một cái gì đó tôi sẽ sử dụng rất nhiều trong .NET 4.0 trong lớp học của tôi mà làm bất kỳ sự phản ánh 'riêng tĩnh readonly ConcurrentDictionary _reflectionCache = new ConcurrentDictionary();' –

4

Singleton không chỉ là lớp tĩnh không thể được kế thừa. Đó là một lớp thông thường có thể được khởi tạo chỉ một lần, với tất cả mọi người chia sẻ cá thể đơn lẻ đó (và làm cho nó an toàn hơn là công việc nhiều hơn).

Mã .NET điển hình cho Singleton trông giống như sau. Đây là một ví dụ nhanh, và không phải bằng bất kỳ phương tiện thực hiện hoặc thread-safe mã tốt nhất:

public sealed class Singleton 
{ 
    Singleton _instance = null; 

    public Singleton Instance 
    { 
     get 
     { 
      if(_instance == null) 
       _instance = new Singleton(); 

      return _instance; 
     } 
    } 

    // Default private constructor so only we can instanctiate 
    private Singleton() { } 

    // Default private static constructor 
    private static Singleton() { } 
} 

Nếu bạn đang đi để đi xuống con đường bạn đang nghĩ, một lớp kín tĩnh sẽ làm việc bình thường.

+0

Tôi nghĩ rằng bạn cần phải sửa đổi mã đó một chút - và trừ khi bạn cẩn thận trong bản sửa đổi, nó sẽ không an toàn về luồng. Tuy nhiên, làm cho nó thread-an toàn thực sự là khá dễ dàng. –

+0

@Jon Tôi đã không đi cho các phiên bản an toàn thread ở đây. Ví dụ nhanh. Tôi biết một cách để làm cho nó an toàn, nhưng tôi muốn được biết về các bản sửa đổi khác (chỉ vì tò mò). –

0

Vì vậy, theo như tôi lo ngại, đây là cách triển khai ngắn gọn và đơn giản nhất của mẫu Singleton trong C#.

http://blueonionsoftware.com/blog.aspx?p=c6e72c38-2839-4696-990a-3fbf9b2b0ba4

Tôi sẽ, tuy nhiên, cho rằng độc thân là mô hình thực sự xấu xí ... Tôi coi chúng là một chất chống mẫu.

http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx

Đối với tôi, tôi thích có một cái gì đó giống như một kho lưu trữ, thực hiện IRepository. lớp học của bạn có thể khai báo phụ thuộc vào IRepository trong các nhà xây dựng và nó có thể được thông qua việc sử dụng Dependency Injection hoặc một trong các phương pháp:

http://houseofbilz.com/archive/2009/05/02.aspx

7

Có một số mẫu mà có thể thích hợp cho bạn, một singleton là một tồi tệ hơn.

Registry

struct Data { 
    public String ProgramName; 
    public String Parameters; 
} 

class FooRegistry { 
    private static Dictionary<String, Data> registry = new Dictionary<String, Data>(); 
    public static void Register(String key, Data data) { 
    FooRegistry.registry[key] = data; 
    } 
    public static void Get(String key) { 
    // Omitted: Check if key exists 
    return FooRegistry.registry[key]; 
    } 
} 

Ưu

  • Dễ dàng chuyển sang một đối tượng Mock cho tự động kiểm tra
  • Bạn vẫn có thể lưu trữ nhiều trường hợp nhưng nếu cần thiết bạn chỉ có một trường hợp .

Nhược

  • Hơi chậm hơn so với một Singleton hoặc một biến toàn cầu

tĩnh Lớp

class GlobalStuff { 
    public static String ProgramName {get;set;} 
    public static String Parameters {get;set;} 
    private GlobalStuff() {} 
} 

Ưu

  • Simple
  • nhanh

Nhược

  • cứng chuyển động để tức là một đối tượng Mock
  • cứng để chuyển sang một loại đối tượng nếu yêu cầu thay đổi

Simple Singleton

class DataSingleton { 
    private static DataSingleton instance = null; 
    private DataSingleton() {] 
    public static DataSingleton Instance { 
    get { 
     if (DataSingleton.instance == null) DataSingleton.instance = new DataSingleton(); 
     return DataSingleton; 
    } 
    } 
} 

Ưu

  • Không thực sự

Nhược

  • Khó để tạo singleton chủ đề, Phiên bản trên sẽ không thành công nếu có nhiều chủ đề truy cập cá thể.
  • Khó chuyển đổi đối tượng giả

Cá nhân tôi thích Mẫu đăng ký nhưng YMMV.

Bạn nên xem xét Dependency Injection vì nó thường được coi là thực hành tốt nhất nhưng nó quá lớn là một chủ đề để giải thích ở đây.

http://en.wikipedia.org/wiki/Dependency_Injection

+0

Tôi nghĩ rằng mô hình singleton của bạn là sai, rằng nếu kiểm tra bên trong của getter không phải là chủ đề an toàn. Bạn muốn thực hiện một singleton như mô tả ở trên bởi @Jon Skeet. Về mặt lý thuyết, 2 luồng có thể nhập getter đó cùng một lúc, cả hai nhìn thấy instance == null và sau đó cả hai thực thi dòng thứ 2 làm cho singleton biến đổi theo luồng cuối cùng. –

+0

@Chris: Tôi đã đề cập rằng việc triển khai này không phải là luồng an toàn trong phần "Nhược điểm". Bộ luật ở đó để giải thích khái niệm, không đưa ra một ví dụ hoàn toàn làm việc. – dbemerlin

+0

@dbemerlin vui lòng sửa mã cho FooRegistry, public static ** Data ** Get (String key) thay vì _void_. Và thực sự cảm ơn cho cái nhìn tổng quan tốt đẹp. –

-1

Sử dụng các tính năng ngôn ngữ của bạn. Triển khai chủ đề an toàn chủ yếu đơn giản là:

public sealed class Singleton 
{ 
    private static readonly Singleton _instance; 

    private Singleton() { } 

    static Singleton() 
    { 
     _instance = new Singleton(); 
    } 

    public static Singleton Instance 
    { 
     get { return _instance; } 
    } 
} 
2

Sử dụng C# 6 Trình khởi chạy tự động thuộc tính.

public sealed class Singleton 
{ 
    private Singleton() { } 
    public static Singleton Instance { get; } = new Singleton(); 
} 

Ngắn gọn và sạch sẽ - Tôi rất sẵn lòng nghe những nhược điểm này.

+1

cho người mới bắt đầu không phải là chủ đề an toàn – JerryGoyal

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