2010-05-18 44 views
8

Làm cách nào để tạo một lớp trừu tượng buộc mỗi lớp dẫn xuất là Singleton? Tôi sử dụng C#.Lớp cơ sở trừu tượng để buộc mỗi lớp dẫn xuất phải là Singleton

+0

Bạn có cần nó trừu tượng không? Bạn có thể tạo một lớp Singleton chung. Mặc dù nó vẫn sẽ có thể instanciate đối tượng của loại T. –

+0

Có. Cơ sở trừu tượng nên buộc các lớp con trở thành singleton. –

Trả lời

2

Khi bạn muốn kiểm tra thời gian biên dịch, điều này là không thể. Với kiểm tra thời gian chạy, bạn có thể thực hiện việc này. Nó không đẹp, nhưng có thể. Dưới đây là ví dụ:

public abstract class Singleton 
{ 
    private static readonly object locker = new object(); 
    private static HashSet<object> registeredTypes = new HashSet<object>(); 

    protected Singleton() 
    { 
     lock (locker) 
     { 
      if (registeredTypes.Contains(this.GetType())) 
      { 
       throw new InvalidOperationException(
        "Only one instance can ever be registered."); 
      } 
      registeredTypes.Add(this.GetType()); 
     } 
    } 
} 

public class Repository : Singleton 
{ 
    public static readonly Repository Instance = new Repository(); 

    private Repository() 
    { 
    } 
} 
+1

Đó không phải là một singleton. Với mẫu đơn, cuộc gọi của bạn tới 'getInstance' sẽ luôn thành công. Đề xuất của bạn thực sự chỉ là một kiểm tra thời gian chạy mà không cung cấp bất kỳ lợi ích nào của mẫu đơn. – ewernli

5

sẽ không hoạt động vì singleton cần ở đâu đó một truy cập tĩnh và không thể bị ép buộc.

để thực hiện singletonimplemention + ví dụ: Implementing the Singleton Pattern in C#

+0

bài viết thực sự rực rỡ. Tôi đã đạt đến kết luận rằng điều này sẽ không thể nhưng tôi vẫn đang tìm kiếm ý tưởng. –

+1

Để tham khảo liên kết được cập nhật là: http://csharpindepth.com/Articles/General/Singleton.aspx – Seph

2

Singleton có nghĩa là có các nhà thầu tư nhân. Nhưng bạn biết rằng các thành viên tư nhân không thể được kế thừa. Trong C++ có các mẫu, vì vậy bạn có thể tạo một singleton từ một lớp mẫu. trong C#, không có các khuôn mẫu, vì vậy bạn phải viết các hàm tạo riêng của bạn cho mọi singleton mà bạn muốn.

1

Các lớp bằng java hoặc C# không phải là "hạng nhất". Phần tĩnh của một lớp không thể được thừa kế hoặc ghi đè bởi các lớp con. Xem this answer để biết thêm chi tiết. Ngoài ra, bạn không có khái niệm về meta-class.

Trong các ngôn ngữ như Smalltalk hoặc Ruby, bạn có thể xác định một metaclass mới Singleton xác định phương thức getInstance. Sau đó, bạn có thể xác định ClassAClassB là trường hợp của metaclass Singleton. Sau đó cả hai lớp sẽ tự động hiển thị phương thức getInstance có thể được sử dụng để tạo các trường hợp objectA hoặc objectB. Đó không phải là mát mẻ? Vâng, trong thực tế bạn không sử dụng metaclass thường xuyên, và singleton thực sự là cách sử dụng duy nhất của chúng có ý nghĩa và tôi biết.

1

Đây là cách (xấu xí) để thực hiện việc này. Nó có thể có thể được đơn giản hóa và cải thiện, nhưng đó là lần đầu tiên tôi đi vào nó.

Ý tưởng đầu tiên là tạo lớp cơ sở thành lớp trừu tượng chung (như đã đề cập trong các chú thích ở trên), nhưng tham số kiểu bị ràng buộc để lấy ra từ chính lớp cơ sở. Điều này cho phép lớp cơ sở xử lý cá thể singleton của kiểu dẫn xuất. Lưu ý tất cả các lớp dẫn xuất phải được niêm phong, giống như với bất kỳ lớp singleton nào.

Tiếp theo, một hàm tạo được bảo vệ được cho phép, nhưng được yêu cầu chấp nhận một thể hiện của một lớp đặc biệt, SingletonKey, là một singleton được sửa đổi. Các lớp có nguồn gốc có quyền truy cập vào định nghĩa lớp SingletonKey, nhưng lớp cơ sở duy trì quyền kiểm soát riêng tư đối với cá thể được phép duy nhất, và do đó xây dựng trên tất cả các đối tượng có nguồn gốc.

Thứ ba, lớp cơ sở sẽ cần có khả năng gọi hàm tạo của lớp dẫn xuất, nhưng điều này hơi phức tạp. Trình biên dịch sẽ phàn nàn nếu bạn cố gắng gọi hàm tạo có nguồn gốc được tạo ra, vì nó không được bảo đảm để tồn tại. Giải pháp là thêm một ủy nhiệm tĩnh mà lớp dẫn xuất phải khởi tạo. Vì vậy, bất kỳ lớp dẫn xuất nào sẽ cần phải cung cấp một phương thức khởi tạo đơn giản. Phương thức khởi tạo này nên được gọi một cách rõ ràng trước khi cố gắng truy cập cá thể lần đầu tiên trong mã, hoặc một lỗi thời gian chạy sẽ dẫn đến.

public abstract class Singleton<T> where T : Singleton<T> 
{ 
    protected Singleton(SingletonKey key) { } 
    private static SingletonKey _key; 
    private static SingletonKey Key 
    { 
     get 
     { 
      if (_key == null) SingletonKey.Initialize(); 
      return _key; 
     } 
    } 
    protected class SingletonKey 
    { 
     private SingletonKey() 
     { 
     } 
     public static void Initialize() 
     { 
      if (_key == null) 
      { 
       _key = new SingletonKey(); 
      } 
     } 
    } 

    protected static Func<SingletonKey, T> Creator; 
    private static T instance; 
    public static T Instance 
    { 
     get 
     { 
      if (instance == null) instance = Creator(Key); 
      return instance; 
     } 
    } 
} 

public class MySingleton : Singleton<MySingleton> 
{ 
    public string Name { get; set; } 
    public static void Initialize() 
    { 
     Creator = (key) => new MySingleton(key); 
    } 
    protected MySingleton(SingletonKey key) : base(key) 
    { 
    } 
} 
0

Tôi tin rằng tôi đã cố gắng đạt được điều gì đó tương tự, tức là thực thi giao diện chung và mẫu đơn trên một nhóm lớp.Đây là giải pháp của tôi:

// Common interface of my singleton classes 
public interface IMySingletonClass 
{ 
    string ValueGetter(); 

    void ValueSetter(string value); 
} 

// Generic abstract base class 
public abstract class Singleton<T>: IMySingletonClass 
{ 
    private static readonly object instanceLock = new object(); 
    private static T instance; // Derived class instance 

    // Protected constructor accessible from derived class 
    protected Singleton() 
    { 
    } 

    // Returns the singleton instance of the derived class 
    public static T GetInstance() 
    { 
     lock (instanceLock) 
     { 
      if (instance == null) 
      { 
       instance = (T)Activator.CreateInstance(typeof(T), true); 
      } 
      return instance; 
     } 
    } 

    // IMySingletonClass interface methods 
    public abstract string ValueGetter(); 

    public abstract void ValueSetter(string value); 
} 

// Actual singleton class 
public class MySingletonClass : Singleton<MySingletonClass> 
{ 
    private string myString; 

    private MySingletonClass() 
    { 
     myString = "Initial"; 
    } 

    public override string ValueGetter() 
    { 
     return myString; 
    } 

    public override void ValueSetter(string value) 
    { 
     myString = value; 
    } 
} 

Dưới đây là một thử nghiệm đơn giản:

class Program 
{ 
    static void Main(string[] args) 
    { 
     MySingletonClass r1 = MySingletonClass.GetInstance(); 
     Console.WriteLine("R1 value = {0}", r1.ValueGetter()); 
     r1.ValueSetter("Changed through R1"); 
     MySingletonClass r2 = MySingletonClass.GetInstance(); 
     Console.WriteLine("R2 value = {0}", r2.ValueGetter()); 

     Console.ReadKey(); 
    } 
} 

Xin lưu ý rằng bạn có thể dễ dàng loại bỏ các giao diện phổ biến từ lớp singleton trừu tượng chung chung nếu bạn chỉ cần cơ bản "mẫu" .

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