惰性初始模式

在程式设计中, 惰性初始是一种拖延战术。在第一次需求出现以前，先延迟创建物件、计算值或其它昂贵程序。
这通常是以一个旗号来实现，用旗号来标示是否完成其程式。每次请求对象时，会先测试此旗号。如果已完成，直接传回，否则当场执行。
对于此想法更一般的论述，可见惰性求值。
对指令式语言，这个模式可能潜藏着危险，尤其是使用共享状态的程式习惯。

**"惰性工厂"**
以设计模式的观点来说，惰性初始通常会和工厂方法模式合作，这结合了三种构想：- 使用一个工厂去得到一个类别的实例（工厂方法模式）。- 将实例存在一个集合中，所以下次要求一个实例却有相同参数时，可以得到同一个实例（可和单例模式来做比较）。- 在第一次时，使用惰性初始来实例化物件（惰性初始模式）。

**示例**

**C#**
Fruit 类别本身在这里不做任合事。_typesDictionary 变数则是一个存 Fruit 实例的 Dictionary 或 Map ，其透过typeName来存取。
using System;
using System.Collections;
using System.Collections.Generic;
public class Fruit
{
private string _typeName;
private static Dictionary _typesDictionary = new Dictionary();
private Fruit(String typeName)
{
this._typeName = typeName;
}
public static Fruit GetFruitByTypeName(string type)
{
Fruit fruit;
if (!_typesDictionary.ContainsKey(type))
{
// 惰性初始
fruit = new Fruit(type);
_typesDictionary.Add(type, fruit);
}
else
fruit = _typesDictionarytype;
return fruit;
}
public static void ShowAll()
{
if (_typesDictionary.Count > 0)
{
Console.WriteLine("Number of instances made = {0}", _typesDictionary.Count);

foreach (KeyValuePair kvp in _typesDictionary)
{
Console.WriteLine(kvp.Key);
}

Console.WriteLine();
}
}
}
class Program
{
static void Main(string args)
{
Fruit.GetFruitByTypeName("Banana");
Fruit.ShowAll();
Fruit.GetFruitByTypeName("Apple");
Fruit.ShowAll();
// returns pre-existing instance from first 
// time Fruit with "Banana" was created
Fruit.GetFruitByTypeName("Banana");
Fruit.ShowAll();
Console.ReadLine();
}
}

**Java**
import java.util.*;

public class Fruit
{
private static final Map types = new HashMap();
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++**
#include 
#include 
#include 

using namespace std;

class Fruit {
public:
static Fruit* getFruit(const string& type);
static void printCurrentTypes();
private:
static map types;
string type;
// note: constructor private forcing one to use static getFruit()
Fruit(const string& t) : type( t ) {}
};
//definition needed for using any static member variable
map 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 = typestype;   // try to find a pre-existing instance, or std::map'll create one if not found

if (!f) {                   // if it was created by map automatically, it'll be pointing to NULL
// 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.empty()) {
cout ::iterator iter = types.begin(); iter != types.end(); ++iter) {
cout 

**Smalltalk**
The following is an example (in Smalltalk) of a typical accessor method to return the value of a variable using lazy initialization. 
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.

**Ruby**
The following is an example (in Ruby) of lazily initializing an authentication token from a remote service like Google. The way that @auth_token is cached is also an example of memoization.
require 'net/http'
class Blogger
def auth_token
@auth_token 
**
(res = Net::HTTP.post_form(uri, params)) &&
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

**Python**
class Fruit:
def __init__(self, type):
self.type = type

class Fruits:
def __init__(self):
self.types = {}

def get_fruit(self, type):
if type not in self.types:
self.typestype = Fruit(type)

return self.typestype
if __name__ == '__main__':
fruits = Fruits()
print fruits.get_fruit('Apple')
print fruits.get_fruit('Lime')

**PHP**
type = $type;
}
public static function getFruit($type)
{
// Lazy initialization takes place here
if(!array_key_exists($type, self::$types)) {
self::$types$type = new Fruit($type);
}
return self::$types$type;
}
public static function printCurrentTypes()
{
echo 'Number of instances made: ' . count(self::$types) . "\n";
foreach(array_keys(self::$types) as $key) echo "$key\n";
echo "\n";
}
}
Fruit::getFruit('Apple');
Fruit::printCurrentTypes();
Fruit::getFruit('Banana');
Fruit::printCurrentTypes();
Fruit::getFruit('Apple');
Fruit::printCurrentTypes();
/OUTPUT:
Number of instances made: 1
Apple
Number of instances made: 2
Apple
Banana
Number of instances made: 2
Apple
Banana
*/
?>

**另见**
 代理模式- 单例模式- Double-checked locking

**外部连结**
 Article " Java Tip 67: Lazy instantiation - Balancing performance and resource usage" by Philip Bishop and Nigel Warren-  Java code examples date=20081118133324 -  Use Lazy Initialization to Conserve Resources date=20191202055631 -  Description from the Portland Pattern Repository date=20110926205839 -  Lazy Initialization of Application Server Services-  Lazy Inheritance in JavaScript date=20100113233021