2009-09-11 12 views
10

की नई सुविधाओं का उपयोग करके डेल्फी में एक सिंगलटन बनाना मैं डेल्फी में एक सिंगलटन बनाना चाहता हूं। मैंने डेल्फी के पुराने संस्करणों का उपयोग करने से पहले ऐसा किया है, और वैश्विक चर (कार्यान्वयन अनुभाग में) का उपयोग करके और उदाहरण की देखभाल करने के लिए प्रारंभिकरण और अंतिमकरण का उपयोग करके समाप्त कर दिया है। इसके अलावा उपयोगकर्ता को एक उदाहरण बनाने से रोकने का कोई तरीका नहीं था क्योंकि आप मानक कन्स्ट्रक्टर को छुपा नहीं सकते थे। मैं सोच रहा था कि क्लास कन्स्ट्रक्टर और विनाशक, और कक्षा चर (ठीक है, इतना नया नहीं), शायद जेनेरिक, जेनेरिक सिंगलटन क्लास बनाने में मदद कर सकता है। मैंने अभी तक अपनी संतुष्टि के लिए कुछ नहीं बनाया है।डी 2009 और डी 2010

उत्तर

3

यह डेल्फी में सही संभाजक और deallocator तरीकों, NewInstance और FreeInstance अधिभावी द्वारा इस का प्रबंधन करने के लिए संभव था।डेल्फी में रचनाकार और विनाशक क्रमशः प्रारंभ और अंतिम रूप देते हैं, वे स्मृति आवंटित या आवंटित नहीं करते हैं, इसलिए रचनाकारों को छिपाने का प्रयास हमेशा थोड़ा गुमराह होता था।

यानी न्यूइन्स्टेंस जैसे ओवरडोड होने पर, किसी भी और सभी रचनाकारों के निःशुल्क उपयोग की अनुमति देना संभव था, जैसे कि यह कक्षा के लिए स्मृति के एक एकल आवंटन के संदर्भ में कभी भी वापस लौटा।

लेकिन बेस क्लास में उपयोग/व्यवहार पैटर्न को लागू करने का प्रयास करना एक गलती है Iho। पैटर्न को समाहित करने के लिए सभी पैटर्न नहीं हैं या विशिष्ट वर्गों की आवश्यकता नहीं है।

इस तरह के मामलों में आप कुछ ऐसी चीज तैयार करते हैं जो अनिवार्य रूप से जटिल है, और जटिलता मेरे अनुभव में त्रुटियों को आकर्षित करती है और अभ्यास की वस्तु पैटर्न पैटर्न कार्यान्वयन में त्रुटियों को खोजने की कोशिश कर रही है और फिर उन लोगों के खिलाफ सुरक्षा उपाय करने की कोशिश कर रही है काम के व्यावहारिक काम के साथ मिलकर त्रुटियों की बजाय, सिंगलटन वर्ग को प्रदर्शन करना था।

यह दूर है, कक्षा के यूएसएजी दस्तावेज़ को दस्तावेज करने के लिए एफएआर सरल और अधिक प्रभावी है। इस पद्धति को लागू करने के लिए एक तकनीक के रूप में

प्रलेखन आवेदन और स्क्रीन VCL में वस्तुओं के लिए 15 साल के लिए दोषरहित काम किया है, उदाहरण के लिए, अनगिनत अन्य एकमात्र कि मैं उन वर्षों में बना लिया है उल्लेख करने के लिए नहीं।

3

एक सिंगलटन के लिए, आप न्यूइन्स्टेंस विधि को ओवरराइड कर सकते हैं। और एक वर्ग चर का उपयोग करें। आप पहले कॉल पर चर बनाते हैं और पॉइंटर को कक्षा में एक दूसरे को कॉल करते हैं।

आपको अंत में इसे नष्ट करने के लिए कभी-कभी कुछ खोजने की आवश्यकता है (शायद अंतिम रूप का उपयोग करके)।

+0

या D2010 में एक वर्ग नाशक। –

8

डेल्फी 2010 में अब तक का सबसे अच्छा और सुरक्षित तरीका वर्ग निर्माता का उपयोग करना है। here देखें - विशेष रूप से नामक अनुच्छेद पढ़ें बेहतर encapsulation

एचटीएच।

+1

यह एक शर्म की बात है कि उन्होंने इस सुविधा को सही तरीके से दस्तावेज करने के लिए परेशान नहीं किया है, या इसे सहायता में "व्हाट्स न्यू" में शामिल किया है। सिंगलटन पर इटालिक भाग के लिए – IanH

7

मैं इंटरफेस का उपयोग करना पसंद करता हूं जब मुझे सिंगलेट की आवश्यकता होती है और कार्यान्वयन अनुभाग में इंटरफ़ेस के कार्यान्वयन को छुपाया जाता है।

  • स्वत: विनाश लाभ जब कार्यक्रम समाप्त हो जाता है।
  • दुर्घटनाग्रस्त रूप से एक TMySingleton बनाने का कोई तरीका नहीं है।

कमियां

  • किसी ने अपने आप ही IMySingleton लागू करने के लिए तय कर सकते हैं।

नोट: मुझे विश्वास है कि सिंगलेट्स के उपयोग को पूर्ण न्यूनतम रखा जाना चाहिए। सब कुछ, सिंगलेट्स गौरवशाली वैश्विक चर से थोड़ा अधिक हैं। यदि और जब आप अपने कोड का परीक्षण इकाई शुरू करते हैं, तो वे एक उपद्रव बन जाते हैं।

unit uSingleton; 

interface 

type 
    ISingleton = interface 
    ['{8A449E4B-DEF9-400E-9C21-93DFA2D5F662}'] 
    end; 

function Singleton: ISingleton; 

implementation 

uses 
    SyncObjs; 

type 
    TSingleton = class(TInterfacedObject, ISingleton); 

var 
    Lock: TCriticalSection; 

function Singleton: ISingleton; 
const 
    _singleton: ISingleton = nil; 
begin 
    if not Assigned(_singleton) then 
    begin 
    Lock.Acquire; 
    try 
     if not Assigned(_singleton) then 
     _singleton := TSingleton.Create(); 
    finally 
     Lock.Release; 
    end; 
    end; 
    Result := _singleton; 
end; 

initialization 
    Lock := TCriticalSection.Create; 
finalization 
    Lock.Free; 

end. 
+0

+1। – mghie

+0

@ मिगी: आप पैटर्न के कार्यान्वयन पर असहमत हैं? –

+0

मैं आपसे सहमत हूं कि सिंगलटन पैटर्न के अधिकांश उपयोग वैश्विक चर की तुलना में कोई प्रगति नहीं हैं। लेकिन अगर कोई उन्हें (किसी भी कारण से) चाहता है, तो एक थ्रेड-सुरक्षित जेनेरिक समाधान आवश्यक होगा। आपका निश्चित रूप से नहीं है, इसलिए आप वास्तव में एक से अधिक उदाहरणों के साथ समाप्त हो सकते हैं। कम से कम यह स्मृति को रिसाव नहीं करता है, जो मैंने बड़े वाणिज्यिक पुस्तकालयों में देखा है, जहां इंटरफेस के बजाय सिंगलटन कार्यान्वयन के लिए वस्तुओं का उपयोग किया जाता है। मोरित्ज़ का समाधान ऐसा लगता है कि यह थ्रेड-सुरक्षित हो सकता है, लेकिन इसे पूरी तरह से जांचना होगा। – mghie

12

तुम सिर्फ एक सादे सिंगलटन की जरूरत है, सबसे आसान तरीका के रूप में plainth ने सुझाव दिया वर्ग निर्माणकर्ता और वर्ग तरीकों का उपयोग करने के लिए है। लेकिन जेनिक्स बहुत मददगार हैं यदि आपको मांग पर निर्माण के साथ सिंगलेट की आवश्यकता है (यानी पहली पहुंच पर)।

निम्नलिखित कोड मेरी उपयोगिता इकाइयों में से एक से लिया गया है; यह मूल रूप से डेल्फी 200 9 के लिए एक सामान्य सिंगलटन कारखाना प्रदान करता है।

interface 

type 
    {$HINTS OFF} 
    { TSingletonInstance<> implements lazy creation, which is sometimes useful for avoiding 
    expensive initialization operations. 
    If you do not require lazy creation and you target only Delphi 2010 onwards, you should 
    use class constructors and class destructors instead to implement singletons. } 
    TSingletonInstance<T: class, constructor> = record 
    private 
    FGuard: IInterface; 
    FInstance: T; 
    function GetInstance: T; 
    function CreateInstance: TObject; 
    public 
    property Instance: T read GetInstance; 
    end; 
    {$HINTS ON} 
    TSingletonFactoryFunction = function: TObject of object; 

{ Private symbols (which are in the interface section because of known limitations of generics) } 
procedure _AllocateSingletonInstance (InstanceRecord: Pointer; Factory: TSingletonFactoryFunction); 

implementation 

{ TSingleton } 

var 
    SingletonCriticalSection: TRTLCriticalSection; 

type 
    TSingletonGuard = class (TInterfacedObject) 
    private 
    FSingletonInstance: TObject; 
    public 
    constructor Create (AInstance: TObject); 
    destructor Destroy; override; 
    end; 

    PUntypedSingletonInstance = ^TUntypedSingletonInstance; 
    TUntypedSingletonInstance = record 
    FGuard: IInterface; 
    FInstance: TObject; 
    end; 

    // TODO: is a lock required for multiple threads accessing a single interface variable? 
procedure _AllocateSingletonInstance (InstanceRecord: Pointer; Factory: TSingletonFactoryFunction); 
var 
    USI: PUntypedSingletonInstance; 
begin 
    USI := PUntypedSingletonInstance (InstanceRecord); 
    EnterCriticalSection (SingletonCriticalSection); 
    if USI.FInstance = nil then 
    begin 
    USI.FInstance := Factory(); 
    USI.FGuard := TSingletonGuard.Create (USI.FInstance); 
    end; 
    LeaveCriticalSection (SingletonCriticalSection); 
end; 

constructor TSingletonGuard.Create (AInstance: TObject); 
begin 
    FSingletonInstance := AInstance; 
end; 

destructor TSingletonGuard.Destroy; 
begin 
    FSingletonInstance.Free; 
    inherited; 
end; 

function TSingletonInstance<T>.GetInstance: T; 
var 
    Factory: TSingletonFactoryFunction; 
begin 
    if FInstance = nil then 
    begin 
    Factory := Self.CreateInstance; // TODO: associate QC report 
    _AllocateSingletonInstance (@Self, Factory); 
    end; 
    Result := FInstance; 
end; 

function TSingletonInstance<T>.CreateInstance: TObject; 
begin 
    Result := T.Create; 
end; 

initialization 
    InitializeCriticalSection (SingletonCriticalSection); 
finalization 
    DeleteCriticalSection (SingletonCriticalSection); 

प्रयोग इस प्रकार है:

type 
    TMySingleton = class 
    public 
    constructor Create; 
    class function Get: TMySingleton; static; 
    end; 

var 
    MySingletonInstance: TSingletonInstance<TMySingleton>; 

class function TMySingleton.Get: TMySingleton; 
begin 
    Result := MySingletonInstance.Instance; 
end; 
+2

ग्रेट कोड मोरित्ज़। –

+0

धन्यवाद। वास्तव में यह सुंदर होगा अगर मैं डी 200 9 के लिए वर्कअराउंड हटा सकता हूं :) –

0

मैं कोड जनरेटर का उपयोग करके सिंगलटन क्लास बनाना पसंद करता हूं। सामान्य के साथ समस्या यह है कि, सभी कोड स्मृति में उत्पन्न होता है, स्रोत फ़ाइल में नहीं। यह डीबगिंग की कठिनाई में वृद्धि करेगा।

4

TObject के विरासत "बनाएं" कन्स्ट्रक्टर को छिपाने का एक तरीका है। यद्यपि पहुंच स्तर को बदलना संभव नहीं है, लेकिन इसे उसी नाम से अन्य सार्वजनिक पैरामीटर रहित विधि से छिपाया जा सकता है: "बनाएं"। यह सिंगलटन वर्ग के कार्यान्वयन को काफी सरल बनाता है। कोड की सादगी देखें:

unit Singleton; 

interface 

type 
    TSingleton = class 
    private 
    class var _instance: TSingleton; 
    public 
    //Global point of access to the unique instance 
    class function Create: TSingleton; 

    destructor Destroy; override; 
    end; 

implementation 

{ TSingleton } 

class function TSingleton.Create: TSingleton; 
begin 
    if (_instance = nil) then 
    _instance:= inherited Create as Self; 

    result:= _instance; 
end; 

destructor TSingleton.Destroy; 
begin 
    _instance:= nil; 
    inherited; 
end; 

end. 

मैं अपने मूल पोस्ट करने के लिए विवरण कहा: http://www.yanniel.info/2010/10/singleton-pattern-delphi.html