Alternativní vytváření objektů

Vytvářecí návrhové vzory

Speciální podskupina návrhových vzorů, která nabízí alternativní způsoby k vytváření objektů, než je prosté volání konstruktoru

  • Singleton: Vytvoření jediné instance třídy, kterou všichni sdílí a snadno k ní přistupují odkudkoli.

  • Builder: Konstrukce složitého objektu po kouscích (např. vytvoření grafu přidáváním uzlů a hran).

  • Prototype: Namísto vytváření nového objektu naklonuj existující objekt.

  • Abstract Factory: Jednotné místo pro vytváření vzájemně kompatibilních instancí různých tříd.

  • Factory Method: Přenechání konstrukce objektu podtřídě.

  • Flyweight: Vytváření a správa sdílených objektů.

Builder

  • Postupné vytváření objektu jiným objektem (builderem) a následné získání hotového objektu.

  • Příkladem je StringBuilder

StringBuilder builder = new StringBuilder("Hello "); // create a builder
builder.append("cruel ").append("world"); // construct an object - a text
builder.append("!");
String result = builder.toString(); // get the final text
  • StringBuilder si průběžně ukládá (ale nespojuje) jednotlivé řetězce

  • Teprve metoda toString vše pospojuje a vrátí

  • Je efektivnější než sčítání, které průběžně spojuje řetězce, tj. vytváří nové a nové objekty (řetězce jsou neměnné)

  • StringBuilder není thread safe, proto existuje její varianta StringBuffer.

Singleton

Runtime rt = Runtime.getRuntime; // every call like this returns the address of the same object - runtime context

Prototype

  • Vytvoření objektu naklonováním jiného již existujícího objektu

  • Každá třída v Javě má metodu clone() poděděnou ze třídy Object.

  • Ale lze definovat i vlastní metodu.

Flyweight

  • Nejedná se přímo o vytvářecí vzor, ale o vzor chování (behavioral). Nicméně jeho funkcí je i vytvářet a vracet objekty.

  • Některé objekty vytváří vždy unikátně (vždy novou instanci třídy), u některých se chová jako Singleton (vrací jeden objekt stále dokola)

  • Příkladem jsou objektové obálky primitivních typů a jejich metoda valueOf

Integer i1 = Integer.valueOf(100); // between -128 and 127
Integer i2 = Integer.valueOf(100);
boolean referencesAreEqual = (i1 == i2); // true

i1 = Integer.valueOf(300);
i2 = Integer.valueOf(300);
boolean referencesNotEqual = (i1 == i2); // false

Proč tak podivné chování?

  • Optimalizace využití paměti: "valueOf() returns an Integer instance representing the specified int value. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range."

  • Třída se tedy chová jako tzv. Flyweight Factory, která některé objekty (flyweigts, zde objekty s hodnotou -128 až 127) kešuje a šetří tak paměť.

  • Úplně stejně se kód bude chovat při auto(un)boxingu, respektive použití konstruktoru, namísto metody valueOf:

Integer i1 = 100; // between -128 and 127
Integer i2 = 100;
boolean referencesAreEqual = (i1 == i2); // true

i1 = 300;
i2 = 300;
boolean referencesNotEqual = (i1 == i2); // false