Kodėl naudoti „getters“ ir „seters / accessors“?

Kokie yra privalumai, kai naudojate „getters“ ir „seters“ - kurie tik gauna ir nustato - vietoj tiesiog kintamųjų laukų šiems kintamiesiems?

Jei gavėjai ir steigėjai kada nors padarė daugiau nei tik gauti / nustatyti, galiu tai suprasti labai greitai, bet aš nesuprantu 100%, kaip:

 public String foo; 

blogiau nei:

 private String foo; public void setFoo(String foo) { this.foo = foo; } public String getFoo() { return foo; } 

Pirmasis priima daug mažesnį šablono kodą.

1321
14 окт. nustatė Dean J spalio 14 d 2009-10-14 21:20 '09 21:20 2009-10-14 21:20
@ 38 atsakymai
  • 1
  • 2

Iš tiesų, yra nemažai priežasčių apsvarstyti priedų naudojimą , o ne tiesioginį klasės laukų kartografavimą - be kapsuliavimo argumento ir palengvinant būsimus pokyčius.

Štai keletas priežasčių, apie kurias žinau:

  • Apsunkinant elgesį, susijusį su nuosavybės įgijimu ar nustatymu, vėliau galite pridėti papildomų funkcijų (pvz., Patvirtinimą).
  • Paslėpti vidinį turto atvaizdavimą atskleidžiant turtą naudojant alternatyvų vaizdą.
  • Atskirkite atvirą sąsają nuo pokyčių, o viešoji sąsaja išlieka pastovi, o diegimas keičiasi, nedarant įtakos esamiems klientams.
  • Gyvenimo ir atminties objekto valdymo semantikos valdymas (pašalinimas) - ypač svarbus aplinkose, kuriose yra nekontroliuojama atmintis (pvz., C ++ arba Objective-C).
  • Debug pertraukos taško suteikimas, kai turto pasikeitimas vykdymo metu - derinimas, kai ir kur turtas, pakeistas į tam tikrą vertę, gali būti gana sudėtingas be jo kai kuriose kalbose.
  • Prisimenama sąveika su bibliotekomis, kurios skirtos dirbti su „getter / seters“ atributais - „Mocking“, „Serialization“ ir „WPF“.
  • Suteikti paveldėtojams galimybę keisti objekto elgesio semantiką ir jam taikomi svarbiausi getter / setter metodai
  • Leisti naudoti getter / setter kaip lambda išraiškas, o ne vertes.
  • Geters ir seters gali leisti skirtingus prieigos lygius - pavyzdžiui, gauti gali būti viešai prieinami, tačiau rinkinys gali būti apsaugotas.
807
14 окт. atsakymas suteiktas LBushkin 14 okt. 2009-10-14 21:47 '09 at 9:47 PM 2009-10-14 21:47

Dėl dviejų savaičių (mėnesių, metų), kai suprasite, kad jūsų seteris turi daryti daugiau nei tik nustatyti vertę, jūs taip pat suprasite, kad turtas buvo naudojamas tiesiogiai 238 kitose klasėse: -)

395
14 окт. atsakymas pateikiamas ChssPly76 14 okt. 2009-10-14 21:23 '09 9:23 PM 2009-10-14 21:23

Atviras laukas yra ne blogesnis nei pora getters / seters, kurie nieko nedaro, bet grąžina lauką ir priskiria jį. Pirma, aišku, kad (daugelyje kalbų) nėra funkcinių skirtumų. Bet kokie skirtumai turėtų būti susiję su kitais veiksniais, pvz., Prieinamumu ar aiškumu.

Dažnai minimas getter / setter poros privalumas nėra. Yra pareiškimas, kad galite pakeisti įgyvendinimą, o jūsų klientai neturėtų būti perskaičiuoti. Tikėtina, kad steigėjai leidžia jums pridėti funkcijų, tokių kaip patvirtinimas, ir jūsų klientams net nereikia apie tai žinoti. Tačiau pridėjus čekį setter'iui, tai yra jo preliminarių sąlygų pasikeitimas, ankstesnės sutarties pažeidimas , kuris buvo gana paprastas: „jūs galite kažką čia įdėti ir tą patį galite gauti vėliau iš getter“.

Taigi, dabar, kai nutraukėte sutartį, pakeiskite kiekvieną kodo bazės failą, o ne vengti. Jei to nepadarysite, darote prielaidą, kad visas kodas numato, kad šių metodų sutartis yra kitokia.

Jei tai nebuvo sutartis, sąsaja leido klientams patalpinti objektą nepriimtinose valstybėse. Kas tiksliai yra kapsulės priešingybė. Jei šis laukas iš tikrųjų negali būti pritaikytas nuo pat pradžių, kodėl nuo pat pradžių nebuvo patikrinimo?

Tas pats argumentas taikomas ir kitiems suvokiamiems šių pasyviųjų „getter / setter“ porų privalumams: jei vėliau nuspręsite pakeisti nustatytą vertę, jūs nutraukiate sutartį. Jei nepaisysite numatytojo funkcionalumo išvestinėje klasėje, o ne kelis nekenksmingus pakeitimus (pvz., Žurnalą ar kitą nepastebimą elgesį), jūs pažeidžiate bazinės klasės sutartį. Tai yra Liškovo pakeitimo principo pažeidimas, kuris laikomas vienu iš OO principų.

Jei klasėje yra šių kvailų getterių ir steigėjų kiekvienam laukui, tai yra klasė, neturinti invariantų, be sutarties. Ar tai tikrai yra objektų orientuotas dizainas? Jei visose klasėse yra tie getters ir seters, tai tik kvailas duomenų turėtojas, o kvailieji duomenų turėtojai turėtų atrodyti kaip kvailieji duomenų turėtojai:

313
24 авг. atsakymą pateikė R. Martinho Fernandes 24 rug. 2012-08-24 13:55 '12, 13:55 pm 2012-08-24 13:55

Daugelis žmonių kalba apie getters ir steigėjų naudą, bet aš noriu žaisti velnio advokatą. Šiuo metu derinu labai didelę programą, kurioje programuotojai nusprendė padaryti visus getarus ir steigėjus. Jis gali atrodyti malonus, tačiau tai yra apsukimas su atvirkštine inžinerija.

Pasakykite, kad naršote šimtus kodų eilučių, ir jūs susiduriate su šia:

 person.name = "Joe"; 

Tai gražus tik kodo gabalas, kol jūs suprasite jo nustatytoją. Dabar sekite šį diegimo programą ir nustatykite, kad jis taip pat nustato person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName ir skambučius person.update (), kuris siunčia užklausą į duomenų bazę ir tt Tai, kur įvyko atminties nutekėjimas.

Vietos kodo fragmento supratimas iš pirmo žvilgsnio yra svarbus geros skaitymo bruožas, kuris sukelia ir įsitvirtina. Štai kodėl aš stengiuosi jų išvengti, kai tik galiu, ir kuo labiau sumažinti jų naudojimą.

76
15 окт. Atsakyti Kai 15 oct. 2009-10-15 00:00 '09 nuo 0:00 2009-10-15 00:00

Grynuose objektuose orientuotame pasaulyje getters ir steigėjai yra baisus anti-modelis . Skaitykite šį straipsnį: Getters / Setters. Blogis Laikotarpis Trumpai tariant, jie skatina programuotojus galvoti apie objektus kaip duomenų struktūras, o tokio pobūdžio mąstymas yra vien procedūrinis (pvz., COBOL arba C). Objektų kalba nėra duomenų struktūros, o tik objektai, kurie atskleidžia elgesį (o ne atributus / savybes!)

Daugiau apie juos galite rasti skyriuje 3.5 „ Elegantiški objektai“ (mano knyga apie objekto programavimą).

45
23 сент. atsakymas pateikiamas rugsėjo 256 d 2014-09-23 19:39 '14, 19:39, 2014-09-23 19:39

Yra daug priežasčių. Mano mėgstamiausia yra tada, kai reikia keisti elgesį arba pakoreguoti kintamąjį. Pavyzdžiui, tarkime, kad jums buvo nustatytas „setSpeed“ („int speed“) metodas. Bet norite nustatyti tik maksimalų greitį 100. Jūs darote kažką panašaus:

 public void setSpeed(int speed) { if ( speed > 100 ) { this.speed = 100; } else { this.speed = speed; } } 

Ką daryti, jei visur jūsų kode naudojote viešąjį lauką ir tada supratote, kad jums reikia pirmiau minėto reikalavimo? Sėkmės medžioti kiekvieną atvirą lauką, o ne tiesiog pakeisti savo setter.

Mano 2 centai :)

43
14 окт. atsakymą pateikė Peter D , spalio 14 d. 2009-10-14 21:27 '09 9:27 pm 2009-10-14 21:27

Vienas iš priedų ir mutatorių privalumų yra tas, kad galite atlikti patikrinimą.

Pavyzdžiui, jei „ foo buvo viešai prieinama, galėčiau lengvai jį nustatyti null ir tada kažkas galėtų pabandyti skambinti į objekto metodą. Bet jis nebėra! Naudodamas „ setFoo metodą galėčiau įsitikinti, kad foo niekada nebuvo nustatyta.

Prietaisai ir mutatoriai taip pat leidžia užklijuoti - jei neturite matyti vertės po to, kai jį įvedėte (tai tikriausiai įdiegta konstruktoriuje ir tada naudojama metodais, bet niekada neturėtų būti keičiama), niekas niekada nematys. Bet jei galite leisti kitoms klasėms matyti ar keisti, galite pateikti atitinkamą priedą ir (arba) mutatorių.

36
14 окт. Atsakyti Thomas Owens 14 spalis 2009-10-14 21:25 '09 21:25 2009-10-14 21:25

Priklauso nuo jūsų kalbos. Jūs pažymėjote šį „į objektą orientuotą“, o ne „Java“, todėl norėčiau pabrėžti, kad atsakymas į „ChssPly76“ priklauso nuo kalbos. Pavyzdžiui, Python'e nėra jokio pagrindo naudoti „getters“ ir „seters“. Jei reikia keisti elgesį, galite naudoti turinį, suvyniojantį „getter“ ir „seteris“, kad pasiektumėte pagrindinį atributą. Kažkas panašaus:

 class Simple(object): def _get_value(self): return self._value -1 def _set_value(self, new_value): self._value = new_value + 1 def _del_value(self): self.old_values.append(self._value) del self._value value = property(_get_value, _set_value, _del_value) 
28
14 окт. jcdyer atsakymas 14 sp 2009-10-14 21:32 '09, 9:32, 2009-10-14 21:32

Na, aš tik noriu pridurti, kad net jei jie kartais yra reikalingi jūsų kintamųjų / objektų kapsuliavimui ir saugumui, jei norime koduoti tikrą objektą orientuotą programą, tada turime sustabdyti priedų klaidas , nes kartais esame labai priklausomi nuo jų, kai tai tikrai nėra būtina, ir beveik lygiai taip pat būtų skelbiami kintamieji.

23
22 авг. Jorge Aguilar rugpjūčio 22 d. Atsakymas 2012-08-22 17:47 '12, 17:47, 2012-08-22 17:47

Vėliau tai žinau, bet manau, kad yra žmonių, kurie domisi našumu.

Aš atlikiau nedidelį našumo testą. Aš parašiau klasę "NumberHolder", kuris, gerai, turi sveiką skaičių. Šį „Integer“ galite perskaityti naudodami „getter anInstance.getNumber() metodą arba tiesiogiai naudodami numerį naudodami „ anInstance.number . Mano programa skaito skaičių 1 000 000 000 kartų abiem kryptimis. Šis procesas kartojamas penkis kartus ir laikas spausdinamas. Gavau tokį rezultatą:

 Time 1: 953ms, Time 2: 741ms Time 1: 655ms, Time 2: 743ms Time 1: 656ms, Time 2: 634ms Time 1: 637ms, Time 2: 629ms Time 1: 633ms, Time 2: 625ms 

(1 laikas yra tiesus kelias, laikas 2 - getter)

Matote, getter yra (beveik) visada šiek tiek greičiau. Tada aš bandžiau naudoti skirtingą skaičių ciklų. Vietoj 1 mln. Naudoju 10 mln. Ir 0,1 mln. Rezultatai:

10 milijonų ciklų:

 Time 1: 6382ms, Time 2: 6351ms Time 1: 6363ms, Time 2: 6351ms Time 1: 6350ms, Time 2: 6363ms Time 1: 6353ms, Time 2: 6357ms Time 1: 6348ms, Time 2: 6354ms 

Su 10 milijonų ciklų laikas yra beveik tas pats. Čia yra 100 tūkst. (0,1 mln.) Ciklų:

 Time 1: 77ms, Time 2: 73ms Time 1: 94ms, Time 2: 65ms Time 1: 67ms, Time 2: 63ms Time 1: 65ms, Time 2: 65ms Time 1: 66ms, Time 2: 63ms 

Be to, esant skirtingam ciklų skaičiui, getter yra šiek tiek greičiau nei įprasta. Tikiuosi, kad tai padėjo jums.

22
30 авг. Atsakymas pateikiamas kangalioo 30 rug . 2016-08-30 21:59 '16 at 21:59 pm 2016-08-30 21:59

Ačiū, tikrai išaiškino mano mąstymą. Dabar čia (beveik) 10 (beveik) įtikinamų priežasčių NEGALI naudoti „getters“ ir „seters“:

  • Kai suprantate, kad jums reikia padaryti daugiau nei tik nustatyti ir gauti vertę, galite tiesiog padaryti, kad laukas būtų privatus.
  • Bet koks jūsų atliktas testas gali būti tik kontekstinis, kuris retai pasitaiko praktikoje.
  • Galite pakeisti nustatytą vertę - tai absoliutus košmaras, kai skambinantysis atsiunčia jums vertę, kurią jie [šoko siaubo] nori išsaugoti kaip IS.
  • Galite paslėpti vidinį vaizdą - fantastišką, todėl įsitikinkite, kad visos šios operacijos yra simetriškos?
  • Jūs atskyrėte savo viešąją sąsają nuo pakeitimų pagal lapus - jei kuriate sąsają ir nesate tikri, kad tiesioginė prieiga prie kažko buvo tvarkinga, tuomet jūs turėjote tęsti projektavimą.
  • Kai kurios bibliotekos tikisi, kad tai, bet ne tiek daug - refleksija, serializacija, šmeižto objektai veikia gerai su viešaisiais laukais.
  • Paveldėdami šią klasę galite nepaisyti numatytųjų funkcijų - kitaip tariant, galite tikrai supainioti skambinančius asmenis, ne tik paslėpti įgyvendinimą, bet ir padaryti jį nesuderinamą.

Paskutiniai trys išėjimai (N / A arba D / C) ...

21
27 марта '12 в 6:53 2012-03-27 06:53 atsakymą pateikė vartotojo595447 kovo 27 d. 12:53 2012-03-27 06:53

Nenaudokite getters, jei tai reikalinga jūsų dabartiniam tiekimui. Ty Nemanykite per daug apie tai, kas nutiks ateityje, jei kas nors pakeis pakeitimo užklausą daugelyje gamybos programų ir sistemų.

Pagalvokite paprastą, paprastą, prireikus pridėkite sudėtingumą.

Nenorėčiau pasinaudoti įmonių savininkų nežinojimu, turinčiu gilias technines žinias, nes manau, kad tai yra teisinga ar man patinka požiūris.

Turiu didžiulę sistemą, parašytą be getter nustatymo, tik su prieigos modifikatoriais ir kai kuriais metodais, skirtais patikrinti biz logikos n vykdymą. Jei jums to reikia. Naudokite viską.

15
14 июля '12 в 19:20 2012-07-14 19:20 atsakymą pateikė Mohamedas liepos 14 d., 12 val

Jau seniai galvoju apie „Java“ programą ir manau, kad tikrosios priežastys yra šios:

  • Sąsajos kodas, o ne įgyvendinimas
  • Sąsajos apibrėžia tik metodus, o ne laukus

Kitaip tariant, vienintelis būdas nurodyti lauką sąsajoje yra naujo metodo rašymo būdas ir dabartinės vertės skaitymo metodas.

Šie metodai yra liūdnas getter ir seteris.

14
08 нояб. atsakymą pateikė Thorbjørn Ravn Andersen . 2009-11-08 00:55 '09 ne 0:55 2009-11-08 00:55

Mes naudojame getters ir seters:

  • pakartotiniam naudojimui
  • tikrinti vėlesniuose programavimo etapuose

Getter ir setter metodai yra viešosios sąsajos, skirtos naudotis privačiais klasės nariais.


Mantracijos inkapsuliavimas

Įgaliotasis užpildymas yra privataus ir viešo lauko kūrimas.

Getter metodai: galime pasiekti privačius kintamuosius.

Setter metodai: galime pakeisti privačius laukus.

Nors „Getter“ ir „Setter“ metodai nesuteikia naujų funkcijų, vėliau galime pakeisti savo nuomonę, kad galėtume atlikti šį metodą

  • geriau
  • saugesnis; ir
  • greičiau

Bet kuriuo atveju galite naudoti vertę, kuri grąžina šią vertę. Vietoj:

 int x = 1000 - 500 

naudoti

 int x = 1000 - class_name.getValue(); 

Kalbant apie laikinąjį

2019

14
02 сент. Atsakyti Devrath Sep 02 2013-09-02 09:51 '13 ne 9:51 2013-09-02 09:51

Tai gali būti naudinga tingus krovimui. Tarkime, kad aptariamas objektas yra saugomas duomenų bazėje ir nenorite jo gauti, jei to nereikia. Jei objektą gauna gavėjas, tada vidinis objektas gali būti nulinis, kol kas nors to neprašys, tada galite jį gauti, kai pirmą kartą skambinate gavėjui.

Aš turėjau pagrindinio puslapio klasę projekte, kuris buvo perduotas man, kuris įkėlė keletą duomenų iš kelių skirtingų interneto paslaugų skambučių, tačiau šių interneto paslaugų skambučių duomenys ne visada buvo naudojami visuose vaikų puslapiuose. Žiniatinklio paslaugos, skirtos visiems privalumams, yra naujų apibrėžimų „lėtas“ pionieriai, todėl nenorite skambinti žiniatinklio paslaugų, jei to nereikia.

Perkėliau iš viešųjų laukų į getters, o dabar geters tikrina talpyklą ir, jei ji neskambina interneto paslauga. Taigi, esant mažoms pakuotėms, buvo užkirstas kelias daugeliui interneto paslaugų.

Taigi getter taupo mane nuo bandymo išsiaiškinti kiekvieną vaiko puslapį, ko man reikia. Jei to reikia, aš vadinu getter ir jis nori, kad jis būtų surastas man, jei to dar neturiu.

  protected YourType _yourName = null; public YourType YourName{ get { if (_yourName == null) { _yourName = new YourType(); return _yourName; } } } 
14
14 окт. atsakymas suteiktas 14 min. 2009-10-14 22:08 '09 10:08 val. 2009-10-14 22:08

Vienas aspektas, kurio iki šiol praleidau, yra prieigos specifikacija:

  • nariams, kuriuos turite konfigūruoti ir gauti, turite tik vieną prieigos specifikaciją
  • steigėjams ir getteriams, galite ją konfigūruoti ir atskirai apibrėžti.
12
14 окт. atsakymas pateikiamas jdehaan 14 oct. 2009-10-14 21:38 '09 9:38 PM 2009-10-14 21:38

Kalbomis, kurios nepalaiko „savybių“ (C ++, Java) arba reikalauja pakartotinio klientų susigrąžinimo keičiant laukų savybes (C #), lengviau modifikuoti gauti / nustatyti metodus. Pavyzdžiui, pridedant patvirtinimo logiką prie setFoo metodo nereikia keisti klasės viešosios sąsajos.

Kalbomis, kurios palaiko „tikrąsias“ savybes (Python, Ruby, galbūt „Smalltalk“?), Nėra prasmės gauti / nustatyti metodus.

10
14 окт. John Millikin atsakymas spalio 14 d 2009-10-14 21:25 '09 21:25 2009-10-14 21:25

Redaguoti: atsakiau į šį klausimą, nes yra daug žmonių, studijuojančių programavimą, klausia, ir dauguma atsakymų yra labai techniškai kompetentingi, tačiau jie nėra taip lengvai suprantami, jei esate pradedantysis. Mes visi buvome nauji, todėl maniau, kad bandysiu savo ranką draugiškiau.

Du pagrindiniai yra polimorfizmas ir patvirtinimas. Net jei tai tik kvailas duomenų struktūra.

Tarkime, mes turime šią paprastą klasę:

 public class Bottle { public int amountOfWaterMl; public int capacityMl; } 

Labai paprasta klasė, kurioje yra skysčio kiekis ir koks jo tūris (mililitrais).

Kas atsitinka, kai darau:

 Bottle bot = new Bottle(); bot.amountOfWaterMl = 1500; bot.capacity = 1000; 

Na, jūs nesitikėjote, kad jis dirbs, tiesa? Norite, kad ten būtų tam tikras sveikatinimo testas. Ir kas blogiau, jei aš niekada nenurodau maksimalaus pajėgumo? O brangūs, mes turime problemų.

Tačiau yra ir kita problema. Ką daryti, jei buteliai buvo tik vieno tipo konteineriai? Что, если бы у нас было несколько контейнеров, все с емкостью и количеством заполненной жидкости? Если бы мы могли просто создать интерфейс, мы могли бы позволить остальной части нашей программы принять этот интерфейс, а бутылки, канистры и всякие вещи просто работали бы взаимозаменяемо. Разве это не было бы лучше? Поскольку интерфейсы требуют методов, это тоже хорошо.