Proč mám rád get a set metody

Ano přiznávám se jsem staromilec. Možná dokonce i zpátečník. Mám rád get a set metody a nerad vidím snahu se jich zbavit. Občas se na internetových diskuzích setkám s návrhy jak „lépe“ řešit přístup k vlastnostem objektu. Dokonce se jeden takový návrh dostal do návrhu změn v Javě 7. Návrhy jsou podobné následujícímu:

Místo

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

budeme psát

public property String foo;

nebo ještě lépe

@property
private String foo;

Tím si ušetříme spoustu práce s nudným psaním get a set metod. Kompilátor všechno krásně vygeneruje za nás.

Nejvíc mi vadí to, že nikde nevidím problém, který se těmito návrhy má řešit. Nikdo přece už dávno get a set metody nepíše, všechno to za nás dělá vývojové prostředí. Napadá mě jediný argument, a to že tím pomůžeme Javě v nesmyslné válce o implementaci čehokoli na co nejméně řádek. Dosáhneme tím o trochu lepší výsledky při porovnávání počtu řádek s implementací v Ruby nebo C#. To si opravdu všichni myslí, že počet potřebných řádek kódu je to co určuje kvalitu jazyka?

Zpět ale k uvedeným návrhům. Odhlédněme od toho, že ve skutečnosti neřeší žádný reálný problém. Podívejme se co by jejich přijetí znamenalo. Za předpokladu, že by za nás get a set metody generoval kompilátor bychom nezískali vůbec nic. To už rovnou můžeme psát

public String foo;

a přistupovat k poli přímo. Jediné v čem by nám „zjednodušený zápis“ mohl pomoci by mohlo být nějaké automagické sledování změn hodnot a generování příslušných událostí. To bych ale raději řešil aspekty.

Co mi na druhou stranu get a set metody přinášejí? To samé co objektově orientované programování! Možnost skrytí implementace, možnost defenzivního programování a obecně možnost volby. Je totiž mnoho případů, kdy get a set metoda nejsou v té triviální podobě tak jak nám je generuje GUI. Často potřebuji zařídit, aby bylo pole jenom pro čtení. Například když píši neměnitelnou (immutable) třídu. V tom případě udělám set metodu private. Nebo ji udělám protected, když chci, aby ji mohly měnit jen spřátelené třídy. Už vidím návrh, že by se to dalo řešit takto:

public property readonly change protected String foo;

Krása. Neřeší to ale defenzivní programování. Případy, kdy místo

public void setDate(Date date)
{
this.date = date;
}

píši

public void setDate(Date date) {
this.date = new Date(date.getTime());
}

To za mě jazyk nemá šanci vyřešit. To si musím napsat sám. Počítač neví, že chci zabránit tomu, aby mi kdokoliv kdykoliv změnil datum, které mám uložené a proto si chci vytvořit defenzivní kopii. Podobně u vracení kolekcí neví, že nechci aby mi ji někdo měnil a chci ji vracet neměnitelnou.

public List getList() {
return Collections.unmodifiableList(list);
}

A to už vůbec nemluvím o kontrole vstupních parametrů přicházejících do set metody.

Teď se můžeme začít hádat o procenta. Kolik je metod, u kterých mi stačí jednoduchý standardní tvar a kolik je těch, které potřebuji nějak modifikovat? Nemohli bychom náhodou tu většinu řešit magickou anotací a těch pár co potřebujeme změnit napsat postaru? Ne nemohli! Dostali bychom dva různé zápisy pro tu samou věc, museli bychom nějak řešit co dělat, když použijeme anotaci i get metodu a ze všeho by vznikl hrozný zmatek. Ano mohlo by to být stejné jako u implicitních konstruktorů, ale nemyslím si, že nám to všechno stojí za to, jenom kvůli pár ušetřeným řádkům kódu.