惰性初始模式

在程式設計中, 惰性初始是一種拖延戰術。在第一次需求出現以前，先延遲建立物件、計算值或其它昂貴程式。這通常是以一個旗號來實現，用旗號來標示是否完成其程式。每次請求物件時，會先測試此旗號。如果已完成，直接傳回，否則當場執行。對於此想法更一般的論述，可見惰性求值。對指令式語言，這個模式可能潛藏著危險，尤其是使用共享狀態的程式習慣。"惰性工廠".以設計模式的觀點來說，惰性初始通常會和工廠方法模式合作，這結合了三種構想：示例.C#.codice_1 類別本身在這裡不做任合事。codice_2 變數則是一個存 codice_1 例項的 Dictionary 或 Map ，其透過codice_4來存取。using System;using System.Collections;using System.Collections.Generic;public class Fruitprivate string _typeName;private static 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);elsefruit = _typesDictionary[type];return fruit;public static void ShowAll()if (_typesDictionary.Count &gt; 0)Console.WriteLine("Number of instances made = {0}", _typesDictionary.Count);foreach (KeyValuePair kvp in _typesDictionary)Console.WriteLine(kvp.Key);Console.WriteLine();class Programstatic 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 createdFruit.GetFruitByTypeName("Banana");Fruit.ShowAll();Console.ReadLine();Java.import java.util.*;public class Fruitprivate static final Map();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 initializationreturn types.get(type);C++.using namespace std;class Fruit {public:static Fruit* getFruit(const string&amp; type);static void printCurrentTypes();private:static map types;string type;// note: constructor private forcing one to use static getFruit()//definition needed for using any static member variablemap 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&amp; type) {Fruit *&amp; f = types[type]; // try to find a pre-existing instance, or std::map'll create one if not foundif (!f) { // if it was created by map automatically, it'll be pointing to NULL// couldn't find one, so make a new instancef = new Fruit(type); // lazy initialization partreturn f;* For example purposes to see pattern in actionvoid Fruit::printCurrentTypes() {if (!types.empty()) {cout « "Number of instances made = " « types.size() « endl;for (map::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 createdFruit::getFruit("Banana");Fruit::printCurrentTypes();return 0;輸出：Number of instances made = 1BananaNumber of instances made = 2AppleBananaNumber of instances made = 2AppleBananaSmalltalk.The following is an example (in Smalltalk) of a typical accessor method to return the value of a variable using lazy initialization.heightheight ifNil: [height := 2.0].^heightThe '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.initializeheight := 2.0height^heightNote 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 Bloggerdef auth_token@auth_token ||=(res = Net::HTTP.post_form(uri, params)) &amp;&amp;get_token_from_http_response(res)end# get_token_from_http_response, uri and params are defined later in the classendb = Blogger.newb.instance_variable_get(:@auth_token) # returns nilb.auth_token # returns tokenb.instance_variable_get(:@auth_token) # returns tokenPython.class Fruit:def __init__(self, type):self.type = typeclass Fruits:def __init__(self):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.header('Content-type:text/plain; charset=utf-8');class Fruitprivate $type;private static $types = array();private function __construct($type)$this-&gt;type = $type;public static function getFruit($type)// Lazy initialization takes place hereif(!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: 1AppleNumber of instances made: 2AppleBananaNumber of instances made: 2AppleBanana?&gt;