Късна инициализация (на английски: Lazy initialization) е създаващ шаблон за дизайн, който се използва в обектно-ориентираното програмиране.
Целта на късната инициализация е да се отложи във времето създаването на обект, изчисляването на стойност или на някакъв друг отнемащ ресурси процес, до момента в който не ни е нужен за първи път.
import java.util.*;
public class Fruit
{
private static final Map<String,Fruit> types = new HashMap<String,Fruit>();
private final String type;
// using a private constructor to force use of the factory method.
private Fruit(String type) {
this.type = type;
}
/**
* Lazy Factory method, gets the Fruit instance associated with a
* certain type. Instantiates new ones as needed.
* @param type Any string that describes a fruit type, e.g. "apple"
* @return The Fruit instance associated with that type.
*/
public static synchronized Fruit getFruit(String type) {
if(!types.containsKey(type))
{
types.put(type, new Fruit(type)); // Lazy initialization
}
return types.get(type);
}
}
Същия пример за C#
using System;
using System.Collections.Generic;
public class Fruit
{
private static Dictionary<string,Fruit> types = new Dictionary<string,Fruit>();
private string type;
/// <summary>
/// using a private constructor to force use of the factory method.
/// </summary>
/// <param name="type">Type of fruit</param>
private Fruit(String type) {
this.type = type;
}
/// </summary>
/// <param name="type">Any string that describes a fruit type, e.g. "apple"</param>
/// <returns>The Fruit instance associated with that type.</returns>
public static Fruit getFruit(string type) {
Fruit f;
if (! types.TryGetValue(type, out f))
{
f = new Fruit(type); // lazy initialization
types.Add(type,f);
}
return f;
}
public static void printCurrentTypes() {
if (types.Count > 0) {
Console.WriteLine("Number of instances made = {0}",types.Count);
foreach (KeyValuePair<string,Fruit> kvp in types)
{
Console.WriteLine(kvp.Key);
}
Console.WriteLine();
}
}
}
class Program
{
static void Main(string[] args)
{
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();
Console.ReadLine();
}
}
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Fruit {
private:
static map<string,Fruit*> types;
string type;
// note: constructor private forcing one to use static getFruit()
Fruit(const string& t) : type(t) {}
public:
static Fruit* getFruit(const string& type);
static void printCurrentTypes();
};
//declaration needed for using any static member variable
map<string,Fruit*> Fruit::types;
/*
* Lazy Factory method, gets the Fruit instance associated with a
* certain type. Instantiates new ones as needed.
* precondition: type. Any string that describes a fruit type, e.g. "apple"
* postcondition: The Fruit instance associated with that type.
*/
Fruit* Fruit::getFruit(const string& type) {
Fruit *& f = types[type]; //try to find a pre-existing instance
if (!f) {
// couldn't find one, so make a new instance
f = new Fruit(type); // lazy initialization part
}
return f;
}
/*
* For example purposes to see pattern in action
*/
void Fruit::printCurrentTypes() {
if (types.size() > 0) {
cout << "Number of instances made = " << types.size() << endl;
for (map<string,Fruit*>::iterator iter = types.begin(); iter != types.end(); ++iter) {
cout << (*iter).first << endl;
}
cout << endl;
}
}
int main(void) {
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();
return 0;
}
/*
OUTPUT:
Number of instances made = 1
Banana
Number of instances made = 2
Apple
Banana
Number of instances made = 2
Apple
Banana
* /
height
height ifNil: [height := 2.0].
^height
The 'non-lazy' alternative is to use an initialization method that is run when the object is created and then use a simpler accessor method to fetch the value.
initialize
height := 2.0
height
^height
Note that lazy initialization can also be used in non-object-oriented languages.
require 'net/http'
class Blogger
def auth_token
return @auth_token if @auth_token
res = Net::HTTP.post_form(uri, params)
@auth_token = get_token_from_http_response(res)
end
# get_token_from_http_response, uri and params are defined later in the class
end
b = Blogger.new
b.instance_variable_get(:@auth_token) # returns nil
b.auth_token # returns token
b.instance_variable_get(:@auth_token) # returns token