热门问题
时间线
聊天
视角
惰性初始化模式
来自维基百科,自由的百科全书
Remove ads
在程式設計中, 惰性初始化(英語:lazy initialization)是一種拖延戰術。在第一次需求出現以前,先延遲創建物件、計算值或其它昂貴程序。這通常是以一個旗號來實現,用旗號來標示是否完成其程式。每次請求對象時,會先測試此旗號。如果已完成,直接傳回,否則當場執行。
對於此想法更一般的論述,可見惰性求值。對指令式語言,這個模式可能潛藏著危險,尤其是使用共享狀態的程式習慣。
"惰性工廠"
示例
在下面的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);
}
}
Remove ads
C++的例子:
import std;
class Fruit {
private:
static std::map<std::string, Fruit*> types;
std::string type_;
// Note: constructor private forcing one to use static |GetFruit|.
Fruit(const std::string& type):
type_{type} {}
public:
// Lazy Factory method, gets the |Fruit| instance associated with a certain
// |type|. Creates new ones as needed.
static Fruit* getFruit(const std::string& type) {
auto [it, inserted] = types.emplace(type, nullptr);
if (inserted) {
it->second = new Fruit(type);
}
return it->second;
}
// For example purposes to see pattern in action.
static void printCurrentTypes() {
std::println("Number of instances made = {}", types.size());
for (const auto& [type, fruit] : types) {
std::println({}, type);
}
std::println();
}
};
// static
std::map<std::string, Fruit*> Fruit::types;
int main(int argc, char* argv[]) {
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();
}
// OUTPUT:
//
// Number of instances made = 1
// Banana
//
// Number of instances made = 2
// Apple
// Banana
//
// Number of instances made = 2
// Apple
// Banana
//
Remove ads
下面的Smalltalk例子,具有典型的訪問子方法,它返回使用惰性初始化的一個變量的值。
height
^height ifNil: [height := 2.0].
非惰性的替代者,使用的初始化方法是在對象被創建時運行的,並且使用簡單的訪問子方法來取回這個值。
initialize
height := 2.0
height
^height
注意惰性初始化也可以用在非物件導向編程語言中。
下面的Ruby例子,具有惰性初始化的來自遠程服務的身份驗證令牌。 @auth_token
被緩存的方式也是記憶化的示例。
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
Remove ads
Python的例子:
class Fruit():
def __init__(self, type_name):
self.type_name = type_name
def __str__(self):
return f'Fruit: {self.type_name}'
class Fruits():
def __init__(self, *args, **kwargs):
self.type_dict = {}
def get_fruit(self, type_name):
if type_name not in self.type_dict:
self.type_dict[type_name] = Fruit(type_name)
return self.type_dict[type_name]
其執行:
>>> fruits = Fruits()
>>> print(fruits.get_fruit('Apple'))
Fruit: Apple
>>> print(fruits.get_fruit('Lime'))
Fruit: Lime
Remove ads
PHP 7.4的惰性初始化的例子:
<?php
header('Content-Type: text/plain; charset=utf-8');
class Fruit
{
private string $type;
private static array $types = array();
private function __construct(string $type)
{
$this->type = $type;
}
public static function getFruit(string $type): Fruit
{
// Lazy initialization takes place here
if (!isset(self::$types[$type])) {
self::$types[$type] = new Fruit($type);
}
return self::$types[$type];
}
public static function printCurrentTypes(): void
{
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
*/
另見
引用
外部連結
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads