In der Computer-Programmierung ist eine verzögerte Initialisierung ein Entwurfsmuster, das die Erstellung eines Objekts, die Berechnung eines Werts oder eines anderen teuren Prozesses erst dann erstellt, wenn es erstmals benötigt wird. Es ist eine Art verzögerte Auswertung, die sich speziell auf die Instanziierung von Objekten oder anderen Ressourcen bezieht.
Eine verzögerte Initialisierung wird erreicht, indem eine Zugriffs-Methode (eine Get-Methode einer Eigenschaft, auch Getter genannt) erweitert wird, um zu überprüfen, ob ein privates Mitglied (Member), das als Cache fungiert, bereits initialisiert wurde. Wenn dies der Fall ist, wird es sofort zurückgegeben. Wenn nicht, wird eine neue Instanz erstellt, in die Member-Variable eingefügt und just-in-time (JIT) zur ersten Verwendung an den Aufrufer zurückgegeben.
Wenn Objekte Eigenschaften haben, die selten verwendet werden, kann dies die Startgeschwindigkeit verbessern. Die durchschnittliche Programmausführung kann in Bezug auf Speicher (für die Bedingungs-Variablen) und Ausführungs-Zyklen (um sie zu überprüfen) etwas schlechter sein. Die Auswirkung auf die Objektinstanziierung wird zeitlich verteilt („amortisiert“) und verzögern nicht in die Startphase des Systems. Damit können die mittleren Antwortzeiten erheblich verbessert werden.
In Multithreading-Code muss der Zugriff auf verzögert-initialisierte Objekte und Status synchronisiert werden, um eine Wettlaufsituation (race condition) zu vermeiden.
Die träge/verzögerte Fabrik („lazy factory“) In einer Software-Entwurfsmuster-Ansicht (eng. „OOP View“) wird die verzögerte Initialisierung häufig zusammen mit einer Fabrikmethode (OOP Muster) verwendet. Dies kombiniert drei Ideen:
Verwendung einer Fabrik-Methode zum Erstellen von Instanzen einer Klasse (factory method pattern) Speichern der Instanzen in einer Zuordnungstabelle und Zurückgeben derselben Instanz an jede Anforderung für eine Instanz mit denselben Parametern (Multiton-Muster) Verwenden der verzögerten Initialisierung zum Instanziieren des Objekts bei der ersten Anforderung (verzögertes Initialisierungsmuster)
Beispiele
ActionScript 3 Folgendes Beispiel zeigt eine Klasse mit verzögerter Initialisierung in ActionScript: package examples.lazyinstantiation { public class Fruit { private var _typeName:String; private static var instancesByTypeName:Dictionary = new Dictionary();
public function Fruit(typeName:String):void
this._typeName = typeName;
public function get typeName():String
return _typeName;
public static function getFruitByTypeName(typeName:String):Fruit
return instancesByTypeName[typeName] ||= new Fruit(typeName);
public static function printCurrentTypes():void
for each (var fruit:Fruit in instancesByTypeName)
// Iteriert über alle Werte trace(fruit.typeName);
Anwendung: package { import examples.lazyinstantiation;
public class Main { public function Main():void
Fruit.getFruitByTypeName("Banane"); Fruit.printCurrentTypes();
Fruit.getFruitByTypeName("Apfel"); Fruit.printCurrentTypes();
Fruit.getFruitByTypeName("Banane"); Fruit.printCurrentTypes();
C In C wird eine verzögerte Auswertung normalerweise in einer einzelnen Funktion oder einer einzelnen Quelldatei unter Verwendung statischer Variablen implementiert.
In einer Funktion: #include <string.h> #include <stdlib.h> #include <stddef.h> #include <stdio.h>
struct fruit { char *name; struct fruit *next; int number; /* Andere Eigenschaften */
struct fruit *get_fruit(char *name) { static struct fruit *fruit_list; static int seq; struct fruit *f; for (f = fruit_list; f; f = f->next) if (0 == strcmp(name, f->name)) return f; if (!(f = malloc(sizeof(struct fruit)))) return NULL; if (!(f->name = strdup(name))) { free(f); return NULL;
f->number = ++seq; f->next = fruit_list; fruit_list = f; return f; }
/* Beispiel Code */
int main(int argc, char *argv[]) { int i; struct fruit *f; if (argc < 2) { fprintf(stderr, "Aufruf: fruits Frucht-Name [...]\n"); exit(1);
for (i = 1; i < argc; i++) { if ((f = get_fruit(argv[i]))) { printf("Frucht %s: Anzahl %d\n", argv[i], f->number);
return 0; } Wenn man stattdessen eine einzelne Quelldatei verwendet, kann der Status von mehreren Funktionen gemeinsam genutzt werden, während er dennoch vor nicht zugehörigen/verwandten Funktionen verborgen bleibt.
fruit.h (Header-Datei): #ifndef _FRUIT_INCLUDED_ #define _FRUIT_INCLUDED_
struct fruit { char *name; struct fruit *next; int number; /* Andere Eigenschaften */
struct fruit *get_fruit(char *name); void print_fruit_list(FILE *file);
#endif /* _FRUIT_INCLUDED_ */ fruit.c: #include <string.h> #include <stdlib.h> #include <stddef.h> #include <stdio.h> #include "fruit.h"
static struct fruit *fruit_list; static int seq;
struct fruit *get_fruit(char *name) { struct fruit *f; for (f = fruit_list; f; f = f->next) if (0 == strcmp(name, f->name)) return f; if (!(f = malloc(sizeof(struct fruit)))) return NULL; if (!(f->name = strdup(name))) { free(f); return NULL;
f->number = ++seq; f->next = fruit_list; fruit_list = f; return f; }
void print_fruit_list(FILE *file) { struct fruit *f; for (f = fruit_list; f; f = f->next) fprintf(file, "%4d %s\n", f->number, f->name); } main.c: #include <stdlib.h> #include <stdio.h> #include "fruit.h"
int main(int argc, char *argv[]) { int i; struct fruit *f; if (argc < 2) { fprintf(stderr, "Aufruf: Frucht-Name [...]\n"); exit(1);
for (i = 1; i < argc; i++) { if ((f = get_fruit(argv[i]))) { printf("Frucht %s: Anzahl %d\n", argv[i], f->number);
printf("Folgende Fruechte wurden generiert:\n"); print_fruit_list(stdout); return 0; }
C# In .Net-Framework 4.0 hat Microsoft eine Lazy Klasse inkludiert, mit der das Verzögertes-Laden durchgeführt werden kann. Unten finden Sie einen Dummy-Code, mit der Klasse Fruit verzögert geladen werden kann. var lazyFruit = new Lazy<Fruit>(); Fruit fruit = lazyFruit.Value; Hier ist ein Beispiel in C#.
Die Fruit Klasse selbst tut an dieser Stelle Nichts. Die Klassen-Variable _typesDictionary ist ein Dictionary/Map mit dem Fruit Instanzen nach typeName gespeichert werden. using System; using System.Collections; using System.Collections.Generic;
public class Fruit { private string _typeName; private static IDictionary<string, Fruit> _typesDictionary = new Dictionary<string, Fruit>();
private Fruit(String typeName)
this._typeName = typeName;
public static Fruit GetFruitByTypeName(string type)
Fruit fruit;
if (!_typesDictionary.TryGetValue(type, out fruit))
// Verzögerte Initialisierung fruit = new Fruit(type);
_typesDictionary.Add(type, fruit);
return fruit;
public static void ShowAll()
if (_typesDictionary.Count > 0)
Console.WriteLine("Anzahl erzeugte Instanzen = {0}", _typesDictionary.Count);
foreach (KeyValuePair<string, Fruit> kvp in _typesDictionary)
Console.WriteLine(kvp.Key);
Console.WriteLine();
public Fruit()
// Wird benötigt, damit dieses Beispiel kompiliert werden kann.
class Program { static void Main(string[] args)
Fruit.GetFruitByTypeName("Banane"); Fruit.ShowAll();
Fruit.GetFruitByTypeName("Apfel"); Fruit.ShowAll();
// Liefert den ersten erzeugten Instanz ("Banane") zurück. Fruit.GetFruitByTypeName("Banane"); Fruit.ShowAll();
Console.ReadLine();
Ein einfaches Beispiel für die verzögerte Initialisierung, mit der Ausnahme, dass hierfür eine Aufzählung für den Typ verwendet wird namespace DesignPatterns.LazyInitialization { public class LazyFactoryObject
//internal collection of items //IDictionaery makes sure they are unique private IDictionary<LazyObjectSize, LazyObject> _LazyObjectList = new Dictionary<LazyObjectSize, LazyObject>();
//enum for passing name of size required //avoids passing strings and is part of LazyObject ahead public enum LazyObjectSize
None, Small, Big, Bigger, Huge
//standard type of object that will be constructed public struct LazyObject
public LazyObjectSize Size; public IList<int> Result;
//takes size and create 'expensive' list private IList<int> Result(LazyObjectSize size)
IList<int> result = null;
switch (size)
case LazyObjectSize.Small: result = CreateSomeExpensiveList(1, 100); break; case LazyObjectSize.Big: result = CreateSomeExpensiveList(1, 1000); break; case LazyObjectSize.Bigger: result = CreateSomeExpensiveList(1, 10000); break; case LazyObjectSize.Huge: result = CreateSomeExpensiveList(1, 100000); break; case LazyObjectSize.None: result = null; break; default: result = null; break;
return result;
//not an expensive item to create, but you get the point //delays creation of some expensive object until needed private IList<int> CreateSomeExpensiveList(int start, int end)
IList<int> result = new List<int>();
for (int counter = 0; counter < (end - start); counter++)
result.Add(start + counter);
return result;
public LazyFactoryObject()
//empty constructor
public LazyObject GetLazyFactoryObject(LazyObjectSize size)
//yes, i know it is illiterate and inaccurate LazyObject noGoodSomeOne;
//retrieves LazyObjectSize from list via out, else creates one and adds it to list if (!_LazyObjectList.TryGetValue(size, out noGoodSomeOne))
noGoodSomeOne = new LazyObject(); noGoodSomeOne.Size= size; noGoodSomeOne.Result = this.Result(size);
_LazyObjectList.Add(size, noGoodSomeOne);
return noGoodSomeOne;
C++ Hier ein Beispiel in C++. #include <iostream> #include <map> #include <string>
class Fruit { public: static Fruit* GetFruit(const std::string& type); static void PrintCurrentTypes();
private: // Note: constructor private forcing one to use static |GetFruit|. Fruit(const std::string& type) : type_(type) {}
static std::map<std::string, Fruit*> types;
std::string type_;
// static std::map<std::string, Fruit*> Fruit::types;
// Lazy Factory method, gets the |Fruit| instance associated with a certain // |type|. Creates new ones as needed. Fruit* Fruit::GetFruit(const std::string& type) { auto [it, inserted] = types.emplace(type, nullptr); if (inserted) { it->second = new Fruit(type);
return it->second; }
// For example purposes to see pattern in action. void Fruit::PrintCurrentTypes() { std::cout << "Number of instances made = " << types.size() << std::endl; for (const auto& [type, fruit] : types) { std::cout << type << std::endl;
std::cout << std::endl; }
int main() { Fruit::GetFruit("Banana"); Fruit::PrintCurrentTypes();
Fruit::GetFruit("Apple"); Fruit::PrintCurrentTypes();
// Returns pre-existing instance from first time |Fruit| with "Banana" was // created. Fruit::GetFruit("Banana"); Fruit::PrintCurrentTypes(); }
// OUTPUT: // // Number of instances made = 1 // Banana // // Number of instances made = 2 // Apple // Banana // // Number of instances made = 2 // Apple // Banana //
Crystal class Fruit private getter type : String @@types = {} of String => Fruit
def initialize(@type) end
def self.get_fruit_by_type(type : String) @@types[type] ||= Fruit.new(type) end
def self.show_all puts "Number of instances made: #{@@types.size}" @@types.each do |type, fruit| puts "#{type}" end puts end
def self.size @@types.size end end
Fruit.get_fruit_by_type("Banana") Fruit.show_all
Fruit.get_fruit_by_type("Apple") Fruit.show_all
Fruit.get_fruit_by_type("Banana") Fruit.show_all Ausgabe: Number of instances made: 1 Banana
Number of instances made: 2 Banana Apple
Number of instances made: 2 Banana Apple
Haxe Beispiel in Haxe class Fruit { private static var _instances = new Map<String, Fruit>();
public var name(default, null):String;
public function new(name:String) { this.name = name;
public static function getFruitByName(name:String):Fruit { if (!_instances.exists(name)) { _instances.set(name, new Fruit(name));
return _instances.get(name);
public static function printAllTypes() { trace([for(key in _instances.keys()) key]);
Anwendung class Test {