惰性初始模式 - 维基百科,自由的百科全书

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

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

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

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

"惰性工廠"

[编辑]

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

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

示例

[编辑]

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();     } } 
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);     } } 
#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 */ 

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.

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 
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 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 */ ?> 

另見

[编辑]

外部連結

[编辑]