2011-06-17 23 views
5

मैं बस सोच रहा था कि मुझे "सामान्य" चर (कक्षा विशेषताओं?) के बजाय कक्षा में संपत्ति का उपयोग क्यों करना चाहिए। मेरा मतलब यह है:कक्षा में संपत्ति का उपयोग क्यों करें?

TSampleClass = class 
    public 
    SomeInfo: integer; 
end; 

TPropertyClass = class 
    private 
    fSomeInfo: integer; 
    public 
    property SomeInfo: integer read fSomeInfo write fSomeInfo; 
end; 

बड़ा अंतर क्या है? मुझे पता है कि मैं क्रमशः संपत्ति प्राप्त करने या सहेजने के लिए गेटर और सेटर विधियों को परिभाषित कर सकता हूं, लेकिन यह भी संभव है कि वेरिएबल "संपत्ति" के बिना भी संभव हो।

मैंने इसका उपयोग करने का प्रयास करने की कोशिश की, लेकिन कुछ भी उपयोगी नहीं हुआ, इसलिए मैं यहां पूछ रहा हूं।

धन्यवाद

+0

मैजिकमास्टर - मुझे यहां कुछ याद आना चाहिए; क्या आप समझा सकते हैं कि आप अपने उदाहरण TSampleClass.SomeInfo के लिए गेटटर और सेटर को कैसे परिभाषित करेंगे, और वास्तव में उन विधियों को बुलाया जाता है जब आप मान निर्दिष्ट करते हैं, या SomeInfo चर से मान पढ़ते हैं? – Stuart

+0

यह प्रश्न देखें: http://stackoverflow.com/q/3963874/267938 –

उत्तर

7

यह सिर्फ एक विशेष मामले के एक बहुत ही सरल उदाहरण है, लेकिन अभी भी, यह एक बहुत ही आम मामला है।

यदि आपके पास दृश्य नियंत्रण है, तो आप एक चर/संपत्ति को बदलते समय नियंत्रण को पुनर्निर्मित करने की आवश्यकता हो सकती है। उदाहरण के लिए, मान लें कि आपके नियंत्रण में BackgroundColor चर/संपत्ति है।

TMyControl = class(TCustomControl) 
public 
    BackgroundColor: TColor; 
... 
end; 

और TMyControl.Paint प्रक्रिया में, आप पृष्ठभूमि BackgroundColor के मूल्य का उपयोग कर रंग:

तरह के एक चर/संपत्ति जोड़ने का सबसे आसान तरीका यह एक सार्वजनिक चर हो जाने के लिए है। लेकिन यह ऐसा नहीं करता है। क्योंकि यदि आप नियंत्रण के उदाहरण के BackgroundColor चर बदलते हैं, तो नियंत्रण स्वयं को पुन: चित्रित नहीं करता है।इसके बजाए, अगली बार जब किसी अन्य कारण से नियंत्रण फिर से चला जाता है तब तक नया पृष्ठभूमि रंग तब तक उपयोग नहीं किया जाएगा।

तो तुम इस तरह यह क्या करना है:

TMyControl = class(TCustomControl) 
private 
    FBackgroundColor: TColor; 
public 
    function GetBackgroundColor: TColor; 
    procedure SetBackgroundColor(NewColor: TColor); 
... 
end; 

जहां

function TMyControl.GetBackgroundColor: TColor; 
begin 
    result := FBackgroundColor; 
end; 

procedure TMyControl.SetBackgroundColor(NewColor: TColor); 
begin 
    if FBackgroundColor <> NewColor then 
    begin 
    FBackgroundColor := NewColor; 
    Invalidate; 
    end; 
end; 

और फिर नियंत्रण का उपयोग प्रोग्रामर MyControl1.GetBackgroundColor का उपयोग रंग प्राप्त करने के लिए, और MyControl1.SetBackgroundColor उपयोग करने के लिए सेट करने के लिए करना पड़ता है यह। वह अजीब है।

गुणों का उपयोग करके, आप दोनों दुनिया के सर्वश्रेष्ठ हो सकते हैं। दरअसल,, वह पढ़ यदि आप देखने के प्रोग्रामर के दृष्टिकोण से

TMyControl = class(TCustomControl) 
private 
    FBackgroundColor: TColor; 
    procedure SetBackgroundColor(NewColor: TColor); 
published 
    property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor; 
end; 

... 

procedure TMyControl.SetBackgroundColor(NewColor: TColor); 
begin 
    if FBackgroundColor <> NewColor then 
    begin 
    FBackgroundColor := NewColor; 
    Invalidate; 
    end; 
end; 

तो

  • कर सकते हैं दोनों और एक ही पहचानकर्ता, MyControl1.BackgroundColor संपत्ति का उपयोग कर पृष्ठभूमि रंग निर्धारित करते हैं, और
  • नियंत्रण जब वह इसे सेट करता है तो उसे पुनर्निर्मित किया जाता है!
+0

मैं एक बहुत ही महत्वपूर्ण बात का उल्लेख करना भूल गया। कुछ अन्य उत्तरों ने इसे छुआ है, लेकिन मैं इसे और अधिक विस्तार से समझाऊंगा: ऑब्जेक्ट इंस्पेक्टर (ओआई) में जो भी संपत्ति आप देखते हैं वह ... संपत्ति है! उपर्युक्त मेरे उदाहरण में, संपत्ति 'पृष्ठभूमि रंग' ओआई में सूचीबद्ध की जाएगी, ताकि आप डिज़ाइन समय पर नियंत्रण की उपस्थिति को बदल सकें। और जब आप मान बदलते हैं, तो संबंधित कोड को डिज़ाइन समय पर नियंत्रण को फिर से निकालने के लिए निष्पादित किया जाता है! यदि आपने संपत्ति का उपयोग नहीं किया था, लेकिन केवल 'गेटबैकग्राउंड कॉलर' फ़ंक्शन और 'सेटबैकग्राउंड कॉलर' प्रक्रिया, ओआई नहीं जानता ... –

+0

... कि नियंत्रण में 'BackgroundColor' नामक एक संपत्ति है, और इसका उपयोग करना चाहिए इसे पढ़ने के लिए 'GetBackgroundColor' फ़ंक्शन' सेट करें और इसे सेट करने के लिए 'SetBackgroundColor' प्रक्रिया का उपयोग करें। यह एक बहुत ही महत्वपूर्ण बात है, मुझे यकीन है कि आप इसकी सराहना करते हैं! दरअसल, शायद आप हर दिन गुणों का उपयोग करते हैं। उदाहरण के लिए, जब आप 'टीबटन 'के' कैप्शन 'को बदलते हैं, तो आप' टीबटन' उदाहरण की 'कैप्शन' प्रॉपर्टी का उपयोग कर रहे हैं। यह शायद फ़ील्ड वैरिएबल से पढ़ता है और इसमें एक सेटर फ़ंक्शन होता है, ताकि आपके द्वारा टाइप किए जाने पर नियंत्रण को फिर से खींचा जा सके (वास्तव में, 'कैप्शन' प्रॉपर्टी' स्ट्रिंग 'नहीं है, लेकिन एक' टीसीएपीशन' ... –

+0

... जिसे 'टाइप टीसीएशन = टाइप स्ट्रिंग' द्वारा परिभाषित किया गया है। इसलिए यह एक स्ट्रिंग है, लेकिन फिर भी एक अलग प्रकार है, और इस प्रकार के लिए ओआई जानता है कि जब भी ओआई में मान बदल जाता है, तो इसे सेटटर का उपयोग करना चाहिए, न केवल जब आप रिटर्न दबाते हैं। लेकिन वह एक sidenote था।) –

4

वहाँ वास्तविक जीवन लाभ हैं:

  • गुण पढ़ने के लिए बदला जा सकता है/लिखने/read'n'write आसानी से, अलग Getters और सभी Setters के साथ परेशानी की आवश्यकता के बिना कोड पर;
  • प्रारंभिक अनुभाग में केवल एक पंक्ति जोड़कर गुणों को बाल कक्षाओं में सार्वजनिक/प्रकाशित किया जा सकता है;
  • फ़ील्ड सेट करने की बात आने पर गुण अधिक अनुकूल होते हैं, "लेबल.फॉन्ट। आकार: 14" "के साथ" लेबल.फॉन्ट.सेट आकार (14) "की तुलना करें, आप"/= "टैब/रिक्त स्थान और कोड के साथ संरेखित कर सकते हैं बहुत अधिक पठनीय होगा;

संपादित करें: एक और चीज जिसे मैंने सोचा था, गुण आपको केवल 1 पैरामीटर के लिए गेट/सेट विधियों को सीमित करने के लिए मजबूर करते हैं, जो ओओपी के लिए अच्छा है। तुलना करें कि कुछ अति-इंजीनियर कार्यों के लिए:

GetItem(Index:integer; ForcedIndex:boolean=false):TItem //Forced index to get any value 
GetItem(Index:integer; out Res:PItem):boolean //Result signals if out pointer is valid 
2

पर एक नज़र यह सिर्फ एक अच्छा प्रोग्रामिंग अभ्यास है ले लो। इसके अलावा, प्रकाशित गुणों के बारे में जानकारी कक्षा के लिए उत्पन्न आरटीटीआई में संग्रहीत की जाती है और उनके नाम, गणना आदि द्वारा पहुंचा जा सकता है। इस सुविधा का उपयोग उदाहरण के लिए किया जाता है जब इसके क्रमबद्ध संसाधन फ़ॉर्म से कोई फॉर्म पढ़ते हैं।

0

आप संपत्ति के बिना एक चर में परिवर्तन की निगरानी नहीं कर सकते हैं।

संपत्ति के लिए आपके पढ़ने/लिखने के लिए एक चर होना आवश्यक नहीं है, वे कार्य हो सकते हैं। और फिर आप किसी संपत्ति के "ऑन चेंज" का प्रबंधन कर सकते हैं।

जैसे

TmyChange = procedure(Sender: Tobject) of object; 


private 
Fchange : TmyChange; 

public 
property SomeInfo: integer read getFoo write setFoo; 
property onChange : TmyChange read Fchange write Fchange; 

function getFoo : integer 
begin 
    return localFoo; 
end; 

function setFoo (value : integer) 
begin 
    // validate incoming value 
    localFoo=value; 
    if assigned(Fchange) then Fchange(self); 
end; 
+1

मुझे एक बग मिला: डेल्फी में, कोई 'वापसी' कथन नहीं है। –

+1

मुझे एक और बग मिला: एक फ़ंक्शन को वापसी मूल्य की आवश्यकता होती है। –

+0

और कोई 'स्व' नहीं है जब तक कि फ़ंक्शन किसी ऑब्जेक्ट की विधि न हो ... –

3

मुझे पता है कि मैं हो रही है या क्रमशः संपत्ति को बचाने के लिए मनुष्य और सेटर तरीके को परिभाषित कर सकते हैं, लेकिन यह भी चर एक "संपत्ति" किया जा रहा बिना संभव है।

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

इसके अलावा, फ़ील्ड और गुणों के बीच एक बड़ा अंतर प्रकाशित होने की क्षमता है और इस प्रकार ऑब्जेक्ट इंस्पेक्टर में उपयोग किया जा सकता है। फ़ील्ड (अन्य प्रकार के वर्ग या इंटरफेस) को प्रकाशित के रूप में घोषित नहीं किया जा सकता है।

संपत्ति भी बहुत महत्वपूर्ण हो सकती है - या उपयोगी हो - विरासत में। तकनीकी रूप से, आप एक संपत्ति को ओवरराइड नहीं कर सकते हैं, लेकिन आप कई तरीकों से ओवरराइड की नकल कर सकते हैं। कुछ उदाहरणों में जहां संपत्ति का नाम TDescendant से कहा जा सकता है, अपने स्वयं के उद्देश्य के साथ प्रत्येक:

1) अमूर्त:

TBase = class(TObject) 
protected 
    function GetName: String; virtual; abstract; 
    procedure SetName(const Value: String); virtual; abstract; 
public 
    property Name: String read GetName write SetName; 
end; 

TDescendant = class(TBase) 
private 
    FName: String; 
protected 
    function GetName: String; override; 
    procedure SetName(const Value: String); override; 
end; 

2 ए) सुरक्षा (क्रोम की तरह उल्लेख किया है,):

TBase = class(TObject) 
private 
    FName: String; 
    function GetName: String; 
    procedure SetName(const Value: String); 
protected 
    property Name: String read GetName write SetName; 
end; 

TDescendant = class(TBase) 
public 
    property Name; 
end; 

2 बी)

TBase = class(TObject) 
private 
    FName: String; 
protected 
    function GetName: String; 
    procedure SetName(const Value: String); 
end; 

TDescendant = class(TBase) 
public 
    property Name: String read GetName write SetName; 
end; 

, आप कर सकते थे ऊपर की combinination तक चांग ई वंश वर्गों के लिए गुणों का व्यवहार।

2

गुणों का उपयोग करने के मुख्य कारणों में से एक (चाहे यह अधिक ओओ है) इनपुट की मान्यता है, उदाहरण के लिए यदि आपको कर्मचारी वर्ग की आयु को 18 वर्ष की वैध सीमा में सीमित करने की आवश्यकता है।40

TEmp = class 
    private 
    FName: string; 
    FAge: Integer; 
    procedure SetAge(const Value: Integer); 
    procedure SetName(const Value: string); 
    published 
    property Name:string read FName write SetName; 
    property Age:Integer read FAge write SetAge; 
    end; 

..... 

procedure TEmp.SetAge(const Value: Integer); 
begin 
    if not (Value in [18..40]) then 
    raise Exception.Create('Age must be between 18 and 40') 
    else 
    FAge := Value; 
end; 
+0

आपके उदाहरण में सत्यापन आपके सेटर का हिस्सा है, आपको एक सेटटर रखने के लिए किसी संपत्ति की आवश्यकता नहीं है, आप केवल अपने सेटर को सार्वजनिक कर सकते हैं (केवल तभी मान्य होगा जब आपको वास्तव में प्रकाशित होने के लिए अपने सेटटर की आवश्यकता हो) – siwmas

संबंधित मुद्दे