Soukromá pole umožňují skrýt stav objektu před externím kódem. Často je však nutné mít k těmto polím přístup. Gettery a settery umožňují kombinovat soukromí polí a možnost přístupu k nim z externího kódu a poskytují řízený přístup k soukromým polím.

Vezměte si například následující třídu Osoba

class Osoba

Zde vám ochrana soukromí umožňuje vyhnout se nastavení polí _name a _age na nesprávné hodnoty, jako je prázdný řetězec pro jméno nebo záporný věk. Bylo by však hezké, kdyby mohli nastavit správné hodnoty nebo jen získat hodnoty. S tím mohou pomoci jak getři, tak setteři.

Getry

Gettry jsou navrženy tak, aby vracely hodnotu. Getter představuje speciální metodu, která používá klíčové slovo get před názvem vlastnosti a vrací hodnotu:

class Osoba

Jsou zde definovány dva getry:

Řetězec získat jméno int získat věk

Getter začíná návratovým typem, za nímž následuje klíčové slovo get a název vlastnosti. A za názvem vlastnosti je blok kódu, kde je hodnota skutečně vrácena. Navíc tato metoda nepřijímá žádné parametry. V tomto případě se název vlastnosti shoduje s názvem pole (bez úvodního podtržítka), jehož hodnota je vrácena, ale je to nepovinné.

To znamená, že zde máme dva getry: vlastnost name vrací hodnotu pole _name a vlastnost age vrací hodnotu pole _age.

Dále v hlavní funkci máme přístup k těmto vlastnostem:

import 'person.dart'; // připojení třídy Osoba void main()

Navíc prostřednictvím getteru můžete hodnotu pouze získat, ale nemůžete ji nastavit.

Stojí za zmínku, že pokud má getter jeden řádek kódu, pak jako každá jiná metoda může být zkrácen:

String get name =>_name; int get věk => _age;

Setři

Setters umožňují nastavit hodnotu pole. Setter představuje speciální metodu, která začíná klíčovým slovem set následovaným názvem vlastnosti. Pak je zde jeden parametr, který představuje hodnotu, která má být nastavena:

set property_name (parametr)

Například definujeme setter ve třídě Person pro nastavení pole _age:

class Osoba_name; int get věk => _age; // setter set age(int value) 0 && value > Osoba(toto._jméno, tento._věk); >

Setter představuje vlastnost stáří. Protože potřebujeme nastavit hodnotu pole _age, parametr setter představuje typ int:

set age(int value) 0 && value >

V setteru kontrolujeme nastavovanou hodnotu. Pokud představuje platný přiměřený věk – od 1 do 110, pak změníme hodnotu pole _age. Pokud je předaná hodnota nesprávná, pak to nemá žádný vliv na pole _age. Tímto způsobem můžeme poskytnout řízený externí přístup k poli _age.

Nyní můžeme změnit hodnotu vlastnosti age (ve skutečnosti pole _age):

import 'person.dart'; // připojení třídy Osoba void main()

Při předání hodnoty vlastnosti age se spustí setter. A pokud je tato hodnota správná, pak nastavovač změní pole _age:

tom.věk = 22; // volání setteru print(tom.age); // 22

Pokud je předána nesprávná hodnota, nic se nezmění:

tom.věk = 100500; // volání setteru print(tom.age); // 22

Vypočítané vlastnosti

vlastnosti lze vypočítat – nepředstavují hodnotu žádného konkrétního pole, ale jsou dynamicky počítány. Například:

class Osoba_name; int get věk => _age; // vypočítané vlastnosti bool get isChild => _age

ČTĚTE VÍCE
Jak určit věk papouška korely?

Zde byla do třídy Osoba přidána vypočítaná vlastnost isChild, která vrací true, pokud je aktuální objekt Person podmíněně potomkem – pokud je mladší 18 let.

bool get isChild => _age < 18;

Tuto vlastnost pak lze použít jako jiné vlastnosti getru:

import 'person.dart'; // připojení třídy Osoba void main()

Veřejná pole nepoužívejte, když opravdu chcete zabalit vnitřní chování třídy. Vezměte si například java.io.BufferedReader. Má následující pole:

private boolean skipLF = false; // If the next character is a line feed, skip it 

skipLF se čte a zapisuje ve všech metodách čtení. Co když externí třída běžící na samostatném vláknu škodlivě upravila stav skipLF uprostřed čtení? BufferedReader určitě udělá ústupek.

Použijte veřejná pole

Vezměte si například tuto třídu Point:

class Point < private double x; private double y; public Point(double x, double y) < this.x = x; this.y = y; >public double getX() < return this.x; >public double getY() < return this.y; >public void setX(double x) < this.x = x; >public void setY(double y) < this.y = y; >> 

Psaní počítání vzdálenosti mezi dvěma body by bylo velmi bolestivé.

Point a = new Point(5.0, 4.0); Point b = new Point(4.0, 9.0); double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2)); 

Třída nemá žádné jiné chování než normální getry a settery. Je přijatelné používat veřejná pole, když třída představuje pouze datovou strukturu a nemá žádnou и nikdy nebude mít takové chování (zde tenké getry a setry ne jsou zvažovány). Tohle se dá napsat lépe:

class Point < public double x; public double y; public Point(double x, double y) < this.x = x; this.y = y; >> Point a = new Point(5.0, 4.0); Point b = new Point(4.0, 9.0); double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2)); 

Ale pamatujte: vaše třída by neměla chybět jen v chování, ale také by měla ne musí mít ne důvody pro budoucí chování.

Je to zcela proti způsobu vytváření objektů struct Java?

třída SomeData1

Vidím třídu s příslušenstvím a mutátory, které vypadají spíše jako Java.

třída SomeData2

Třída z prvního příkladu je notačně vhodná.

// a function in a class public int f(SomeData1 d) < return (3 * d.x) / d.y; >

Není to tak pohodlné.

// a function in a class public int f(SomeData2 d) < return (3 * d.getX()) / d.getY(); >

Re: aku, izb, John Topley.

Pozor na problémy s variabilitou.

Mohlo by se zdát rozumné vynechat getry/settery. V některých případech to může být normální. Skutečným problémem zde zobrazeného navrženého modelu je variabilita.

Problém je, že předáváte odkaz na objekt, který obsahuje nedokončená veřejná pole. Kdokoli spojený s tímto odkazem může tato pole volně měnit. Stav tohoto objektu již neřídíte. (Přemýšlejte o tom, co by se stalo, kdyby byly řetězce proměnlivé.)

To se zhorší, když je tento objekt důležitou součástí vnitřního stavu jiného, ​​právě jste objevili interní implementaci. Abyste tomu zabránili, musíte místo toho vrátit kopii objektu. To funguje, ale může to mít za následek masivní GC tlak z tuny jednorázových kopií.

ČTĚTE VÍCE
Jak často se mohou habešské kočky koupat?

Pokud máte veřejná pole, zvažte, zda není třída pouze pro čtení. Přidejte pole jako parametry do konstruktoru a označte pole jako konečná. V opačném případě se ujistěte, že nevystavujete vnitřní stav, a pokud potřebujete vytvořit nové instance pro návratovou hodnotu, ujistěte se, že nebude příliš volána.

Viz: Efektivní Java od Joshuy Blocha – Bod č. 13: Přízeň neměnnosti.

PS: Také mějte na paměti, že všechny JVM v dnešní době optimalizují getMethod, pokud je to možné, což má za následek pouze jeden příkaz pro čtení pole.

Aspektově orientované programování vám umožňuje zachytit přiřazení nebo výběry a připojit k nim logiku zachycení, což je podle mého názoru správný způsob, jak problém vyřešit. (Otázka, zda by měly být veřejné nebo chráněné nebo chráněné balíčky, je ortogonální.)

Začnete tedy nesouvislými poli s příslušným kvalifikátorem přístupu. Jak rostou požadavky vašeho programu, připojujete logiku pro případnou kontrolu, kopírování vráceného objektu atd.

Filozofie getter/setter ukládá náklady na velký počet jednoduchých případů, kdy nejsou potřeba.

Zda je styl aspektů čistší nebo ne, je poněkud kvalitativní. Bylo by pro mě snadné vidět pouze proměnné ve třídě a podívat se na logiku samostatně. Ve skutečnosti je raison d'etre programování orientovaného na Apect v tom, že mnoho problémů je průřezových a jejich oddělení ve třídě tříd jako takové není ideální (psaní jako příklad – pokud chcete vše protokolovat, pak Java chce, abyste napsali celou řadu getterů a udržovali je v synchronizaci, ale AspectJ vám umožňuje používat jeden řádek).

Problém IDE je červený sleď. Nejde ani tak o psaní, jako o čtení a vizuální znečištění, které pochází z get/setů.

Anotace se na první pohled zdají podobné programování orientovanému na poměr stran, ale vyžadují, abyste vyčerpávajícím způsobem vyjmenovali body cut přidáním anotací, na rozdíl od stručné specifikace bodového řezu AspectJ.

Doufám, že povědomí o AspectJ zabrání lidem předčasně se usadit v dynamických jazycích.

Můžete vytvořit jednoduchou třídu s veřejnými poli a bez metod v Javě, ale stále je to třída a stále se s ní zachází syntakticky az hlediska alokace paměti jako s třídou. Je nemožné skutečně replikovat struktury v Javě.

Pokud je způsob Java způsobem OO, pak ano, vytvoření třídy s veřejnými poli porušuje zásady týkající se skrývání informací, které říkají, že objekt by měl spravovat svůj vlastní vnitřní stav. (Protože na vás neházím jen žargon, výhodou skrývání informací je, že vnitřní fungování třídy je skryto za rozhraním – řekněme, že jste chtěli změnit mechanismus, kterým vaše třída struct uložila jedno ze svých polí, Pravděpodobně bych se musel vrátit a změnit všechny třídy, které třídu používají.)

Nemůžete také využít podporu tříd, které jsou kompatibilní s názvy JavaBean, což může ublížit, pokud se rozhodnete, řekněme, použít třídu na stránce JavaServer, která je napsána pomocí výrazového jazyka.

Pokud neimplementujete přístupové a mutátorové metody, může vás také zajímat článek JavaWorld Why Getter and Setter Methods are an Evil .

ČTĚTE VÍCE
V jakém věku by měl být mops kastrován?

Pokud píšete malé řešení a chcete minimalizovat množství souvisejícího kódu, cesta Java nemusí být tou správnou cestou – myslím, že vždy záleží na vás a na problému, který se snažíte vyřešit.

Zde vytvářím program pro zadání jména a věku 5 různých osob a třídění (podle věku). K provedení kompletní operace jsem použil třídu, která funguje jako struktura (jako programovací jazyk C) a hlavní třída. Zde uvádím kód.

import java.io.*; class NameList < String name; int age; >class StructNameAge < public static void main(String [] args) throws IOException < NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object NameList temp=new NameList(); // Create a temporary object of the structure BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); /* Enter data into each radix of 'nl' object */ for(int i=0; i/* Perform the sort (Selection Sort Method) */ for(int i=0; inl[j].age) < temp=nl[i]; nl[i]=nl[j]; nl[j]=temp; >> > /* Print each radix stored in 'nl' object */ for(int i=0; i > 

Výše uvedený kód je bez chyb a testován. Stačí jej zkopírovat a vložit do vašeho IDE a . Víš co.

Používejte zdravý rozum. Pokud máte něco jako:

veřejná třída ScreenCoord2D

Pak nemá smysl je oblbovat getry a setry. Nikdy nebudete ukládat souřadnice x,y v celých pixelech jiným způsobem. Getry a settery vás jen zpomalí.

Na druhou stranu s:

bankovní účet veřejné třídy

Možná budete chtít někdy v budoucnu změnit způsob výpočtu zůstatku. Mělo by to opravdu používat getry a settery.

Vždy je lepší vědět proč použijete osvědčené postupy, abyste věděli, kdy je v pořádku pravidla ohýbat.

Jako u většiny věcí, i zde platí obecné pravidlo a pak jsou tu zvláštní okolnosti. Pokud vytvoříte uzavřenou zachycenou aplikaci, abyste věděli, jak bude daný objekt použit, můžete využít více svobody ke zlepšení viditelnosti a/nebo efektivity. Pokud vyvíjíte třídu, kterou budou veřejně používat ostatní mimo vaši kontrolu, přikloňte se k modelu getter/setter. Jako u všech věcí, stačí použít zdravý rozum. Často je v pořádku udělat první kolo s publikováním a později je změnit na getter/setters.

Někdy takovou třídu používám, když potřebuji vrátit více hodnot z metody. Takový objekt je samozřejmě krátkodobý a má velmi omezenou viditelnost, takže by mělo být vše v pořádku.

Mimochodem, struktura, kterou uvádíte jako příklad, již existuje v knihovně základních tříd Java jako java.awt.Point . Má x a y jako veřejná pole, zkontrolujte si to sami.

Pokud víte, co děláte, a ostatní ve vašem týmu to vědí, pak je dobré mít veřejná pole. Ale neměli byste se na ně spoléhat, protože mohou způsobit bolesti hlavy, jako v případě chyb zahrnujících vývojáře používající objekty, jako by byly alokovány na zásobníkech (objekty Java jsou vždy odesílány do metod jako reference, nikoli jako kopie) .

Na tomto typu kódu není nic špatného za předpokladu, že autor to ví představují struktury (nebo datové přenosy) místo objektů. Mnoho vývojářů Java nedokáže rozlišit dobře vytvořený objekt (nejen podtřídu java.lang.Object, ale pravda objekt v konkrétní doméně) a ananas. Takže nakonec vytvářejí struktury, když potřebují předměty a naopak.

ČTĚTE VÍCE
Jaké kapky lze dát kočce do nosu?

Velmi stará otázka, ale dovolte mi ještě jeden krátký příspěvek. Java 8 zavádí lambda výrazy a odkazy na metody. Lambda výrazy mohou být spíše doporučeními jednoduchých metod než deklarováním „skutečného“ těla. Ale nemůžete "převést" pole na odkaz na metodu. Tím pádem

stream.mapToInt(SomeData1::x) 
stream.mapToInt(SomeData2::getX) 

Zdá se, že mnoho lidí v Javě není obeznámeno s pokyny Sun Java Coding Guidelines, které říkají, že je zcela vhodné použít proměnnou veřejné instance, když je třída v podstatě „Struct“, pokud Java podporuje „struct“ (pokud neexistuje žádné chování ).

Lidé mají tendenci považovat getry a settery za způsob Javy, jako by byli v centru Javy. To je špatně. Pokud se budete řídit pokyny Sunu pro kódování Java tím, že použijete proměnné veřejné instance ve vhodných situacích, napíšete ve skutečnosti lepší kód, než abyste jej zaplňovali zbytečnými getry a settery.

Java Code Conventions z roku 1999 a stále se nezměnily.

10.1. Poskytování přístupu k instancím tříd a proměnným

Nedovolte, aby byla jakákoli proměnná instance nebo třídy bez dobrého důvodu veřejně dostupná. Instanční proměnné často nemusí být explicitně nastaveny nebo získány - často tak činí jako vedlejší efekt volání metod.

Jedním příkladem vhodných veřejných instančních proměnných je situace, kdy je třída v podstatě datová struktura bez jakéhokoli chování. Jinými slovy, pokud jste místo třídy používali konstrukt (pokud je podporována Java), pak má smysl zveřejnit proměnné instance třídy .

Problém s používáním přístupu s otevřeným polem je stejný problém jako při použití nové, nikoli tovární metody – pokud si to později rozmyslíte, všichni stávající předplatitelé budou přerušeni. Takže z hlediska evoluce API se obecně doporučuje zakousnout se a používat getry/settery.

Jedním z míst, kde jdu opačným směrem, je, když přísně řídíte přístup ke třídě, například ve vnitřní statické třídě používané jako interní datová struktura. V tomto případě by bylo mnohem jasnější použít přístup do terénu.

Mimochodem, podle e-barteku je velmi nepravděpodobné, že IMO přidá podporu vlastností v Javě 7.

Chcete-li vyřešit problémy s variabilitou, můžete prohlásit x a y za konečné. Například:

class Data < public final int x; public final int y; public Data( int x, int y)< this.x = x; this.y = y; >> 

Volací kód, který se pokusí zapsat do těchto polí, obdrží chybu při kompilaci "pole x deklarované jako konečné nelze přiřadit."

Klientský kód by pak mohl mít "krátké" pohodlí, které jste popsal ve svém příspěvku

public class DataTest < public DataTest() < Data data1 = new Data(1, 5); Data data2 = new Data(2, 4); System.out.println(f(data1)); System.out.println(f(data2)); >public int f(Data d) < return (3 * d.x) / d.y; >public static void main(String[] args) < DataTest dataTest = new DataTest(); >> 

To je otázka na objektově orientovaný design, ne na jazyk Java. Obecně se doporučuje skrýt datové typy v rámci třídy a vystavit pouze ty metody, které jsou součástí API třídy. Pokud vystavíte interní datové typy, nemůžete je v budoucnu nikdy změnit. Pokud je skryjete, vaší jedinou povinností vůči uživateli jsou metody návratu a argumentů metody.

ČTĚTE VÍCE
Co dělat, když má pes slzící oči?

Toto je společné téma. Nevýhodou vytváření veřejných polí v objektech je, že nemáte žádnou kontrolu nad hodnotami, které jsou v nich nastaveny. Ve skupinových projektech, kde je mnoho programátorů sdílejících stejný kód, je důležité vyhnout se vedlejším účinkům. Někdy je také lepší vrátit kopii objektu pole nebo jej nějakým způsobem transformovat. Takové metody můžete ve svých testech zesměšňovat. Pokud vytvoříte novou třídu, nemusí se vám zobrazit všechny možné akce. Je to podobné jako u defenzivního programování – gettery a settery mohou být někdy užitečné a jejich vytvoření a použití nestojí mnoho. Proto jsou někdy užitečné.

V praxi má většina polí jednoduché getry a settery. Možné řešení by vypadalo takto:

public property String foo; a->Foo = b->Foo; 

Aktualizace: Je nepravděpodobné, že podpora vlastností bude přidána do Java 7 nebo možná někdy. Ostatní jazyky JVM ​​jako Groovy, Scala atd. nyní tuto funkci podporují. - Alex Miller

Nevidím škodu, pokud víte, že to bude vždy jednoduchá struktura a že k ní nikdy nebudete chtít připojovat chování.

Zkoušel jsem to na několika projektech, na teorii, že getry a nastavovače zahlcují kód sémanticky nesmyslnými zvraty a obraty a že jiné jazyky, jak se zdá, odvádějí skvělou práci se skrýváním dat na základě konvence nebo oddělováním problémů (např. krajta).

Jak je uvedeno výše, čelíte dvěma problémům, které nelze vyřešit:

  • Téměř každý automatizovaný nástroj ve světě java je založen na konvenci getter/setter. Stejně jako ostatní poznamenali, značky jsp, jarní konfigurace, nástroje Eclipse atd., atd. Boj s tím, co vaše nástroje očekávají, že uvidí, je receptem na dlouhé sezení trollingem přes Google, který se snaží najít ten nekonvenční způsob, jak iniciovat jarní fazole. Za ty potíže to opravdu nestojí.
  • Jakmile budete mít svou elegantně nakódovanou aplikaci se stovkami veřejných proměnných, s největší pravděpodobností najdete alespoň jednu situaci, kdy jsou nedostatečné - kde nutně potřebujete neměnnost nebo potřebujete vyvolat nějakou událost, když je nastavena proměnná, nebo chcete vyvolat výjimku, když se proměnná změní, protože nastaví stav objektu na něco ošklivého. Pak jste uvízli u nezáviděníhodné volby mezi zahlcováním kódu speciální metodou všude, kde se proměnná přímo odkazuje, a speciální formou přístupu pro 3 z 1000 proměnných ve vaší aplikaci.

A to je v nejlepším případě scénář úplné práce v autonomním soukromém projektu. Jakmile toto vše exportujete do veřejné knihovny, tyto problémy se ještě zvětší.

Java je velmi podrobná a to je lákavé. Nedělej to.

Tento vzor často používám při vytváření soukromých vnitřních tříd pro zjednodušení kódu, ale nedoporučoval bych takové objekty vystavovat veřejnému rozhraní API. Obecně platí, že čím častěji můžete objekty ve vašem veřejném API nastavit jako neměnné, tím lépe a je nemožné sestavit váš „strukturovaný“ objekt neměnným způsobem.

Kromě toho, i kdybych měl napsat tento objekt jako soukromou vnitřní třídu, stále bych poskytl konstruktor pro zjednodušení kódu pro inicializaci objektu. Mít 3 řádky kódu pro získání užitečného objektu, když se tak stane, je prostě chaotické.