在程式設計中, **惰性初始**是一種拖延戰術。在第一次需求出現以前，先延遲創建物件、計算值或其它昂貴程序。

這通常是以一個旗號來實現，用旗號來標示是否完成其程式。每次請求對象時，會先測試此旗號。如果已完成，直接傳回，否則當場執行。

對於此想法更一般的論述，可見惰性求值。

對指令式語言，這個模式可能潛藏著危險，尤其是使用共享狀態的程式習慣。

"惰性工廠"
------

以設計模式的觀點來說，惰性初始通常會和工廠方法模式合作，這結合了三種構想：

* 使用一個工廠去得到一個類別的實例（工廠方法模式）。
* 將實例存在一個集合中，所以下次要求一個實例卻有*相同*參數時，可以得到*同一個*實例（可和單例模式來做比較）。
* 在第一次時，使用惰性初始來實例化物件（惰性初始模式）。

示例
--

### 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<string, Fruit> \_typesDictionary = new Dictionary<string, Fruit>();

 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 = \_typesDictionary[type];

 return fruit;
 }

 public static void ShowAll()
 {
 if (\_typesDictionary.Count > 0)
 {
 Console.WriteLine("Number of instances made = {0}", \_typesDictionary.Count);
 
 foreach (KeyValuePair<string, Fruit> 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<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++

```
#include <iostream>
#include <string>
#include <map>
 
using namespace std;
 
class Fruit {
 public:
 static Fruit\* getFruit(const string& type);
 static void printCurrentTypes();

 private:
 static map<string,Fruit\*> 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<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, 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 << "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;
}

/\*
輸出：
Number of instances made = 1
Banana
 
Number of instances made = 2
Apple
Banana
 
Number of instances made = 2
Apple
Banana
\*/

```

### 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
</source>
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.

<source lang="smalltalk">
    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.types[type] = Fruit(type)
        
        return self.types[type]

if \_\_name\_\_ == '\_\_main\_\_':
    fruits = Fruits()
    print fruits.get\_fruit('Apple')
    print fruits.get\_fruit('Lime')

```

### PHP

```
<?php
header('Content-type:text/plain; charset=utf-8');

class Fruit
{
    private $type;
    private static $types = array();

    private function \_\_construct($type)
    {
        $this->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 （页面存档备份，存于）
* Use Lazy Initialization to Conserve Resources （页面存档备份，存于）
* Description from the Portland Pattern Repository （页面存档备份，存于）
* Lazy Initialization of Application Server Services
* Lazy Inheritance in JavaScript （页面存档备份，存于）

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
软件设计模式 |
| --- |
|  |
| 设计模式 | 

|  |  |
| --- | --- |
| 创建型 | 
* 抽象工厂
* 生成器
* 工厂方法
* 惰性初始
* 原型
* 单例

 |
|  |
| 结构型 | 
* 适配器
* 桥接
* Composite（英语：）
* 修饰
* 外观
* 享元
* 代理

 |
|  |
| 行为型 | 
* 责任链
* 命令
* Interpreter（英语：）
* 迭代器
* 中介者
* Memento（英语：）
* 观察者
* Specification（英语：）
* State（英语：）
* 策略
* 模板方法
* 访问者

 |

 |
|  |
| 并行模式 | 
* 主动对象（英语：）
* 阻止（英语：）
* Binding properties（英语：）
* 双重检查锁定模式
* 异步方法调用
* Future与promise
* Guarded suspension（英语：）
* Join（英语：）
* 锁
* Messaging（英语：）
* 监视器
* Proactor（英语：）
* 反应器
* 读写锁
* 调度
* 线程池
* 线程局部存储

 |
|  |
| 架构模式 | 
* ADR（英语：）
* 主动记录
* Broker（英语：）
* 主從式架構
* cbd
* DAO
* DDD
* Data transfer object（英语：）
* Front controller（英语：）
* Identity map（英语：）
* Interceptor（英语：）
* 控制反转
* MVC
* 微服務
* MVP
* 單體式應用程式
* 多层架构
* *n*-tier（英语：）
* Naked objects（英语：）
* P2P
* 发布/订阅
* REST
* SOA
* Specification（英语：）

 |
|  |
| 云分布式 | 
* 断路器
* CQRS（英语：）
* 补偿交易（英语：）
* 索引表
* 领导者选举（英语：）
* MapReduce
* 物化视图（英语：）
* 管道
* 过滤器（英语：）
* 发布/订阅
* 分片（英语：）
* 节流（英语：）

 |
|  |
| 其他模式 | 
* Blackboard（英语：）
* Business delegate（英语：）
* Composite entity（英语：）
* 委托
* 依赖注入
* Intercepting filter（英语：）
* 惰性載入
* Method chaining（英语：）
* 模拟对象
* 空对象
* 对象池
* Servant（英语：）
* Twin（英语：）
* Type tunnel（英语：）

 |
|  |
| 书籍 | 
* 设计模式：可复用面向对象软件的基础
* 企业集成模式（英语：）

 |
|  |
| 人物 | 
* 克里斯托佛·亚历山大
* 埃里希·伽瑪
* Ralph Johnson（英语：）
* John Vlissides（英语：）
* 葛來迪·布區
* 肯特·貝克
* 沃德·坎宁安
* 马丁·福勒
* Robert Martin（英语：）
* Jim Coplien（英语：）
* Douglas Schmidt（英语：）
* Linda Rising

 |
|  |
| 社区 | 
* The Hillside Group（英语：）
* The Portland Pattern Repository（英语：）

 |

 |