2010-11-17 29 views
23

Tôi cần một lớp đơn để được khởi tạo với một số đối số. Con đường tôi đang làm nó bây giờ là:Singleton với tham số

class SingletonExample 
{ 
    private SingletonExample mInstance; 
    //other members... 
    private SingletonExample() 
    { 

    } 
    public SingletonExample Instance 
    { 
     get 
     { 
       if (mInstance == null) 
       { 
        throw new Exception("Object not created"); 
       } 
       return mInstance; 
     } 
    } 

    public void Create(string arg1, string arg2) 
    { 
     mInstance = new SingletonExample(); 
     mInstance.Arg1 = arg1; 
     mInstance.ObjectCaller = new ObjectCaller(arg2); 
     //etc... basically, create object... 
    } 
} 

Các ví dụ được tạo ra 'muộn', có nghĩa là tôi không có tất cả các đối số cần thiết khi khởi động ứng dụng.

Nói chung tôi không thích bắt buộc đặt hàng các cuộc gọi phương thức, nhưng tôi không thấy cách khác ở đây. IoC cũng sẽ không giải quyết nó, vì tôi có thể đăng ký nó trong thùng chứa, tôi cũng có thể gọi Create() ...

Bạn có coi đây là kịch bản OK không? Bạn có ý tưởng nào khác không?

chỉnh sửa: Tôi biết rằng những gì tôi viết là một ví dụ nó không đề an toàn, thread-safe không phải là một phần của câu hỏi

+0

đó là * không * một singleton. đâu là loại trừ lẫn nhau? (tức là 'khóa'). cộng với 'getter' của bạn cho cá thể nên tạo cá thể, không phải là ctor - đó là toàn bộ điểm. – RPM1984

+0

Tôi đồng ý với RPM1984, đây không phải là singleton. Các đối số của bạn có thể thay đổi hay chúng sẽ giống nhau trong suốt thời gian tồn tại của ứng dụng của bạn? Một singleton không nên phụ thuộc vào một biến nào đó, nó có thể phụ thuộc vào cấu hình hoặc một singleton khác. Tuy nhiên, thực sự nghĩ rằng thông qua thiết kế của bạn và tự hỏi mình nếu nó là một singleton bạn cần. Hơn sử dụng đơn là thực sự xấu cho thiết kế của bạn. –

+1

Đó là singleton alright, tôi tin rằng :) getter' không thể tạo ra các ví dụ vì nó không có đối số - nó có thể có, nhưng nó chỉ thuận tiện hơn để viết nó như thế này. Và, các đối số, một khi thu được không thay đổi. – veljkoz

Trả lời

18

Một Singleton có tham số có mùi cá.

Hãy xem xét câu trả lời whateva và đoạn mã sau:

Singleton x = Singleton.getInstance("hello", "world"); 
Singleton y = Singleton.getInstance("foo", "bar"); 

Rõ ràng, x == công trình y và y với các thông số tạo ra x, trong khi các thông số tạo y của chỉ đơn giản là bỏ qua. Kết quả có lẽ ... ít gây nhầm lẫn.

Nếu bạn thực sự, thực sự giảm như bạn phải làm điều đó, làm điều đó như thế này:

class SingletonExample 
{ 
    private static SingletonExample mInstance; 
    //other members... 
    private SingletonExample() 
    { // never used 
     throw new Exception("WTF, who called this constructor?!?"); 
    } 
    private SingletonExample(string arg1, string arg2) 
    { 
     mInstance.Arg1 = arg1; 
     mInstance.ObjectCaller = new ObjectCaller(arg2); 
     //etc... basically, create object...  
    } 
    public static SingletonExample Instance 
    { 
     get 
     { 
       if (mInstance == null) 
       { 
        throw new Exception("Object not created"); 
       } 
       return mInstance; 
     } 
    } 

    public static void Create(string arg1, string arg2) 
    { 
     if (mInstance != null) 
     { 
      throw new Exception("Object already created"); 
     } 
     mInstance = new SingletonExample(arg1, arg2);    
    } 
} 

Trong một môi trường đa luồng, thêm đồng bộ để tránh điều kiện chủng tộc.

+6

-1 Tôi không đồng ý giải pháp vì tôi nghĩ bạn đang đề nghị sử dụng đĩa đơn không nên sử dụng. singleton là một lớp chỉ cho phép một cá thể đơn lẻ được tạo ra, và thường cho phép truy cập đơn giản vào cá thể đó Nếu cùng một cá thể được truy cập cho tất cả các yêu cầu có cùng tham số, mẫu nhà máy là thích hợp. có thể gọi Create (.....) như nhiều lần bạn muốn phá vỡ tính bất biến của lớp. –

+6

Massimiliano, trong giải pháp của tôi, bạn có thể gọi tạo chính xác một lần. Và tôi nghĩ rằng việc nhắn tin của tôi làm cho nó đủ rõ ràng rằng tôi không thực sự thích thú với ý tưởng về những người đơn tham số. –

+0

@Massimiliano Peluso - bây giờ ** rằng ** là một quan sát hữu ích - một nhà máy ... những gì tôi sau là thực sự là một kết hợp của singleton/nhà máy, mà thực sự nhọt xuống IoC ... Dù sao, tôi nghĩ rằng tôi có câu trả lời của tôi ngay bây giờ. Cảm ơn – veljkoz

0

Tôi thực sự không thể nhìn thấy một singleton trong mã của bạn. Sử dụng phương thức getInstance tĩnh, được tham số hóa trả về singleton và tạo nó nếu nó chưa được sử dụng trước đó. câu trả lời

4

tốt hơn:

  1. Tạo một giao diện: ISingleton (có chứa bất cứ hành động mà bạn muốn nó làm gì để)

  2. Và kiểu của bạn: Singleton : ISingleton

  3. Giả sử bạn có thể vào UnityContainer:

IUnityContainer _singletonContainer = new UnityContainer(); // or whatever code to initialize the container

  1. Khi bạn đã sẵn sàng để tạo ra sử dụng loại bạn (giả sử bạn đang sử dụng Unity cho DI):

_singletonContainer.RegisterType(typeof(ISingleton), new Singleton(params));

  1. Nếu bạn muốn lấy singleton chỉ cần sử dụng:

var localSingletonVar = _singletonContainer.Resolve<ISingleton>();

Lưu ý: Nếu vùng chứa không có loại được đăng ký cho giao diện ISingleton, thì nó phải ném ngoại lệ, hoặc trả về null.

Cũ Trả lời:

public class Singleton 
{ 

    private static Singleton instance = null; 

    private Singleton(String arg1, String arg2) 
    { 
    } 

    public static Singleton getInstance(String arg1, String arg2) 
    { 
     if (instance != null) 
     { 
      throw new InvalidOperationException("Singleton already created - use getinstance()"); 
     } 
     instance = new Singleton(arg1, arg2); 
     return instance; 
    } 

    public static Singleton getInstance() 
    { 
     if (instance == null) 
      throw new InvalidOperationException("Singleton not created - use GetInstance(arg1, arg2)"); 
     return instance; 
    } 
} 

Tôi muốn đi với một cái gì đó tương tự (bạn có thể cần phải kiểm tra nếu dụ được tạo ra quá), hoặc, nếu container DI của bạn hỗ trợ ném ngoại lệ đối với các loại phi đăng ký, tôi sẽ đi với điều đó.

ATTN: Mã an toàn không an toàn :)

+0

nơi nào bạn tạo một thể hiện của lớp ??? –

+0

cảm ơn vì đã đánh máy typo –

22

Singleton là xấu xí nhưng do một người dùng whateva không thể bị làm phiền để sửa mã riêng của mình ...

public class Singleton 
{ 
    private static Singleton _instance = null; 

    private static Object _mutex = new Object(); 

    private Singleton(object arg1, object arg2) 
    { 
     // whatever 
    } 

    public static Singleton GetInstance(object arg1, object arg2) 
    { 
     if (_instance == null) 
     { 
      lock (_mutex) // now I can claim some form of thread safety... 
      { 
       if (_instance == null) 
       { 
        _instance = new Singleton(arg1, arg2); 
       } 
      } 
     } 

     return _instance; 
    } 
} 

Skeet viết blog về năm này trước, tôi nghĩ, đó là khá đáng tin cậy. Không có ngoại lệ cần thiết, bạn không phải trong kinh doanh của việc nhớ những gì các đối tượng được coi là singletons và xử lý bụi phóng xạ khi bạn nhận được nó sai.

Chỉnh sửa: loại không liên quan sử dụng những gì bạn muốn, object chỉ được sử dụng tại đây để thuận tiện.

+0

Bây giờ, đó là một singleton, không phải là tôi sử dụng chúng một cách rõ ràng (tôi cho DI làm chúng, và chỉ cho những thứ như đăng nhập). +1 – RPM1984

+0

Tôi sẽ tiếp tục và giả định rằng whateva quyết định từ chối câu trả lời đúng về mặt chức năng. Đi đội. – annakata

+0

không, anh ta không (nhìn vào hồ sơ của mình). dù sao đi nữa, tất cả những cuộc nói chuyện này của singleton đã khiến tôi buồn ngủ, tôi đi ngủ. :) – RPM1984

2

Giải pháp khóa đơn đôi được cung cấp bởi annakata sẽ không hoạt động mọi lúc trên mọi nền tảng. có một lỗ hổng trong cách tiếp cận này cũng được ghi chép lại. Không sử dụng cách tiếp cận này hoặc bạn sẽ kết thúc với các vấn đề.

Cách duy nhất để giải quyết vấn đề này là sử dụng từ khóa dễ bay hơi, ví dụ:

private static volatile Singleton m_instance = null; 

Đây là phương pháp tiếp cận an toàn chủ đề duy nhất.

2

Nếu bạn đang sử dụng .NET 4 (hoặc cao hơn), bạn có thể sử dụng loại System.Lazy. Nó sẽ chăm sóc cho bạn các vấn đề an toàn chủ đề và làm điều đó lười biếng, do đó bạn sẽ không tạo ra dụ không cần thiết. Cách này mã ngắn gọn và sạch sẽ.

public sealed class Singleton 
{ 
    private static readonly Lazy<Singleton> lazy = 
     new Lazy<Singleton>(() => new Singleton(),LazyThreadSafetyMode.ExecutionAndPublication); 

    private Singleton() { } 

    public static Singleton Instance { get { return lazy.Value; } } 
} 
Các vấn đề liên quan