Късна инициализация (шаблон)

Късна инициализация (на английски: 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