Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

В компьютерном программировании , ленивая инициализация является тактикой затягивания создания объекта , то вычисления значения , или каким - либо другой дорогостоящего процесса , пока впервые не нужно. Это своего рода ленивая оценка, которая относится конкретно к созданию экземпляров объектов или других ресурсов.

Обычно это достигается путем расширения метода доступа (или средства получения свойства), чтобы проверить, был ли уже инициализирован частный член, действующий как кеш. Если есть, то сразу же возвращают. В противном случае создается новый экземпляр, помещается в переменную-член и возвращается вызывающей стороне точно в срок для его первого использования.

Если объекты имеют редко используемые свойства, это может повысить скорость запуска. Средняя средняя производительность программы может быть немного хуже с точки зрения памяти (для переменных состояния) и циклов выполнения (для их проверки), но влияние создания экземпляра объекта распределяется во времени («амортизируется»), а не концентрируется на этапе запуска система, и, таким образом, среднее время отклика может быть значительно улучшено.

В многопоточном коде доступ к лениво инициализированным объектам / состоянию должен быть синхронизирован для защиты от условий гонки .

«Ленивая фабрика» [ править ]

В представлении шаблона проектирования программного обеспечения отложенная инициализация часто используется вместе с шаблоном фабричного метода . Это объединяет три идеи:

  • Использование фабричного метода для создания экземпляров класса ( фабричный шаблон метода )
  • Сохранение экземпляров на карте и возврат одного и того же экземпляра в каждый запрос для экземпляра с одинаковыми параметрами ( многотонный шаблон )
  • Использование ленивой инициализации для создания экземпляра объекта при первом запросе (шаблон ленивой инициализации)

Примеры [ править ]

ActionScript 3 [ править ]

Ниже приведен пример класса с отложенной инициализацией, реализованной в ActionScript :

 примеры пакетов . ленивое создание { открытый  класс  Fruit  { частный  var  _typeName : String ; частный  статический  var  instanceByTypeName : Dictionary  =  new  Dictionary (); публичная  функция  Fruit ( typeName : String ) : void { this . _typeName  =  typeName ; }публичная  функция  получить  typeName () : String  { return  _typeName ; } общедоступная  статическая  функция  getFruitByTypeName ( typeName : String ) : Fruit { return  instanceByTypeName [ typeName ]  || =  new  Fruit ( typeName ); } общедоступная  статическая  функция  printCurrentTypes () : void { для  каждого  ( var  fruit : Fruit  in  instanceByTypeName )  { // итерация по трассировке каждого значения ( fruit . typeName ); } } } }

Основное использование:

package { импортные  примеры . ленивое создание ;публичный  класс  Main  { публичная  функция  Main () : void { Fruit . getFruitByTypeName ( "Банан" ); Фрукты . printCurrentTypes (); Фрукты . getFruitByTypeName ( "Яблоко" ); Фрукты . printCurrentTypes (); Фрукты . getFruitByTypeName ( "Банан" ); Фрукты . printCurrentTypes (); } } }

C [ править ]

В C ленивое вычисление обычно реализуется внутри одной функции или одного исходного файла с использованием статических переменных .

В функции:

#include  <string.h>#include  <stdlib.h>#include  <stddef.h>#include  <stdio.h>struct  fruit  {  char  * name ;  struct  fruit  * next ;  int  число ;  / * Другие участники * / };struct  fruit  * get_fruit ( char  * name )  {  статическая  структура  фрукта  * fruit_list ;  статический  int  seq ;  struct  fruit  * f ;  for  ( f  =  fruit_list ;  f ;  f  =  f -> next )  if  ( 0  ==  strcmp ( name ,  f -> name ))  return  f ; если  ( ! ( f  =  malloc ( sizeof ( struct  fruit ))))  return  NULL ;  если  ( ! ( е -> имя  =  strdup ( имя )))  {  бесплатно ( е );  return  NULL ;  }  f -> число  =  ++ seq ;  е -> следующий  =  список фруктов ;  fruit_list  =  f ; return  f ; }/ * Пример кода * /int  main ( int  argc ,  char  * argv [])  {  int  я ;  struct  fruit  * f ;  если  ( argc  <  2 )  {  fprintf ( stderr ,  "Использование: фрукты имя-фрукта [...] \ n " );  выход ( 1 );  }  for  ( i  =  1 ;  i  <  argc ;  i ++ )  {  if  ((f  =  get_fruit ( argv [ i ])))  {  printf ( "Fruit% s: number% d \ n " ,  argv [ i ],  f -> number );  }  }  return  0 ; }

Вместо этого использование одного исходного файла позволяет разделить состояние между несколькими функциями, при этом скрывая его от несвязанных функций.

fruit.h:

#ifndef _FRUIT_INCLUDED_ #define _FRUIT_INCLUDED_struct  fruit  {  char  * name ;  struct  fruit  * next ;  int  число ;  / * Другие участники * / };struct  fruit  * get_fruit ( char  * имя ); void  print_fruit_list ( ФАЙЛ  * файл );#endif / * _FRUIT_INCLUDED_ * /

Fruit.c:

#include  <string.h>#include  <stdlib.h>#include  <stddef.h>#include  <stdio.h>#include  "fruit.h"статическая  структура  fruit  * fruit_list ; статический  int  seq ;struct  fruit  * get_fruit ( char  * name )  {  struct  fruit  * f ;  for  ( f  =  fruit_list ;  f ;  f  =  f -> next )  if  ( 0  ==  strcmp ( name ,  f -> name ))  return  f ;  если  ( ! ( f  =  malloc ( sizeof ( struct фрукты ))))  return  NULL ;  если  ( ! ( е -> имя  =  strdup ( имя )))  {  бесплатно ( е );  return  NULL ;  }  f -> число  =  ++ seq ;  е -> следующий  =  список фруктов ;  fruit_list  =  f ;  return  f ; }void  print_fruit_list ( ФАЙЛ  * файл )  {  struct  fruit  * f ;  for  ( f  =  fruit_list ;  f ;  f  =  f -> next )  fprintf ( file ,  "% 4d% s \ n " ,  f -> число ,  f -> имя ); }

main.c:

#include  <stdlib.h>#include  <stdio.h>#include  "fruit.h"int  main ( int  argc ,  char  * argv [])  {  int  я ;  struct  fruit  * f ;  если  ( argc  <  2 )  {  fprintf ( stderr ,  "Использование: фрукты имя-фрукта [...] \ n " );  выход ( 1 );  }  for  ( i  =  1 ;  i  <  argc ;  i ++ )  {  if  ((f  =  get_fruit ( argv [ i ])))  {  printf ( "Fruit% s: number% d \ n " ,  argv [ i ],  f -> number );  }  }  printf ( "Получены следующие плоды: \ n " );  print_fruit_list (стандартный вывод );  возврат  0 ; }

C # [ править ]

В .NET Framework 4.0 Microsoft включила Lazyкласс, который можно использовать для отложенной загрузки. Ниже приведен фиктивный код, который выполняет ленивую загрузку класса.Fruit

var  lazyFruit  =  new  Lazy < Fruit > (); Fruit  fruit  =  lazyFruit . Стоимость ;

Вот фиктивный пример на C # .

Сам Fruitкласс здесь ничего не делает. Переменная класса _typesDictionary - это словарь / карта, используемая для хранения Fruitэкземпляров typeName.

используя  Систему ; using  System.Collections ; using  System.Collections.Generic ;открытый  класс  Fruit {  частная  строка  _typeName ;  частный  статический  IDictionary < string ,  Fruit >  _typesDictionary  =  new  Dictionary < string ,  Fruit > (); частный  фрукт ( String  typeName )  {  this . _typeName  =  typeName ;  } общедоступный  статический  Fruit  GetFruitByTypeName ( строковый  тип )  {  Fruit  fruit ; if  (! _typesDictionary . TryGetValue ( type ,  out  fruit ))  {  // Ленивая инициализация  fruit  =  new  Fruit ( type ); _typesDictionary . Добавить ( вид ,  фрукт );  }  вернуть  фрукты ;  } public  static  void  ShowAll ()  {  if  ( _typesDictionary . Count  >  0 )  {  Console . WriteLine ( "Количество созданных экземпляров = {0}" ,  _typesDictionary . Count );  foreach  ( KeyValuePair < string ,  Fruit >  kvp  в  _typesDictionary )  {  Console . WriteLine ( квп . Ключ );  }  Консоль . WriteLine ();  }  }  public  Fruit ()  {  // требуется для компиляции образца  } }class  Program {  static  void  Main ( string []  args )  {  Fruit . GetFruitByTypeName ( «Банан» );  Фрукты . ShowAll (); Фрукты . GetFruitByTypeName ( «Яблоко» );  Фрукты . ShowAll (); // возвращает уже существующий экземпляр  // при  первом создании Fruit с "Banana" Fruit . GetFruitByTypeName ( «Банан» );  Фрукты . ShowAll (); Консоль . ReadLine ();  } }

Довольно простой пример шаблона проектирования отложенной инициализации с заполнением пробелов, за исключением того, что в нем используется перечисление для типа

namespace  DesignPatterns.LazyInitialization {  public  class  LazyFactoryObject  {  // внутренняя коллекция элементов  // IDictionaery гарантирует, что они являются уникальными  частными  IDictionary < LazyObjectSize ,  LazyObject >  _LazyObjectList  =  new  Dictionary < LazyObjectSize ,  LazyObject > (); // перечисление для передачи имени требуемого размера  // избегает передачи строк и является частью LazyObject впереди  публичного  перечисления  LazyObjectSize  {  None ,  Small ,  Big ,  Bigger ,  Huge  } // стандартный тип объекта, который будет  создан public  struct  LazyObject  {  public  LazyObjectSize  Size ;  public  IList < int >  Результат ;  } // принимает размер и создает «дорогой» список  private  IList < int >  Result ( LazyObjectSize  size )  {  IList < int >  result  =  null ; переключатель  ( размер )  {  case  LazyObjectSize . Маленький :  результат  =  CreateSomeExpectList ( 1 ,  100 );  перерыв ;  case  LazyObjectSize . Большой :  результат  =  CreateSomeExrivateList ( 1 ,  1000 );  перерыв ;  case  LazyObjectSize . Больше :  результат  =  CreateSomeExuritiesList ( 1 ,  10000 );  перерыв;  case  LazyObjectSize . Огромный :  результат  =  CreateSomeExuritiesList ( 1 ,  100000 );  перерыв ;  case  LazyObjectSize . Нет :  результат  =  ноль ;  перерыв ;  по умолчанию :  результат  =  ноль ;  перерыв ;  } вернуть  результат ;  } // создание элемента не является дорогостоящим, но вы понимаете,  // что создание дорогостоящего объекта  откладывается до тех пор, пока не понадобится частный  IList < int >  CreateSomeExuritiesList ( int  start ,  int  end )  {  IList < int >  result  =  new  List < int > ( ); for  ( int  counter  =  0 ;  counter  <  ( end  -  start );  counter ++)  {  результат . Добавить ( начало  +  счетчик );  } вернуть  результат ;  } public  LazyFactoryObject ()  {  // пустой конструктор  } public  LazyObject  GetLazyFactoryObject ( LazyObjectSize  size )  {  // да, я знаю, что это неграмотный и неточный  LazyObject  noGoodSomeOne ; // извлекает LazyObjectSize из списка через out, иначе создает его и добавляет в список  if  (! _LazyObjectList . TryGetValue ( size ,  out  noGoodSomeOne ))  {  noGoodSomeOne  =  new  LazyObject ();  noGoodSomeOne . Размер =  размер ;  noGoodSomeOne . Результат  =  это . Результат ( размер ); _LazyObjectList . Добавить ( размер ,  noGoodSomeOne );  } return  noGoodSomeOne ;  }  } }

C ++ [ править ]

Вот пример на C ++ .

#include  <iostream>#include  <карта>#include  <строка>class  Fruit  {  public :  static  Fruit *  GetFruit ( const  std :: string &  type );  static  void  PrintCurrentTypes (); private :  // Примечание: конструктор private заставляет использовать static | GetFruit |.  Fruit ( const  std :: string &  type )  :  type_ ( тип )  {} статические  типы std :: map < std :: string ,  Fruit *>  ; std :: string  type_ ; };// статический std :: map < std :: string ,  Fruit *>  Fruit :: types ;// Метод Lazy Factory, получает | Fruit | экземпляр, связанный с определенным // | типом |. При необходимости создает новые. Fruit *  Fruit :: GetFruit ( const  std :: string &  type )  {  auto  [ it ,  вставлено ]  =  типы . emplace ( тип ,  nullptr );  если  ( вставлено )  {  это -> второй  =  новый  фрукт ( тип );  } вернуть  его -> второй ; }// Например, чтобы увидеть образец в действии. void  Fruit :: PrintCurrentTypes ()  {  std :: cout  <<  "Количество созданных экземпляров ="  <<  типов . size ()  <<  std :: endl ;  for  ( const  auto &  [ type ,  fruit ]  :  types )  {  std :: cout  <<  type  <<  std :: endl ;  }  std ::cout  <<  std :: endl ; }int  main ()  {  Fruit :: GetFruit ( "Банан" );  Fruit :: PrintCurrentTypes (); Fruit :: GetFruit ( «Яблоко» );  Fruit :: PrintCurrentTypes (); // Возвращает уже существующий экземпляр с первого раза | Fruit | с "Бананом"  // было создано.  Fruit :: GetFruit ( «Банан» );  Fruit :: PrintCurrentTypes (); }// ВЫХОД: // // Количество созданных экземпляров = 1 // Банан // // Количество созданных экземпляров = 2 // Apple // Банан // // Количество созданных экземпляров = 2 // Apple // Банан / /

Кристалл [ править ]

 Тип частного получателя class Fruit  : String @@ types = {} of String => Fruit            def  инициализировать ( @type )  конец def  self . get_fruit_by_type ( тип  :  String )  @@ types [ type ]  || =  Fruit . новый ( тип )  конец def  self . show_all  помещает  "Количество созданных экземпляров: # { @@ types . size } "  @@ types . каждый  делать  | сорт ,  фруктовый |  кладет  конец " # { type } "  кладет конец   def  self . размер  @@ типы . размер  конец конецФрукты . get_fruit_by_type ( "Банан" ) Фрукты . показать всеФрукты . get_fruit_by_type ( "Яблоко" ) Фрукты . показать всеФрукты . get_fruit_by_type ( "Банан" ) Фрукты . показать все

Выход:

Количество изготовленных экземпляров: 1БананКоличество изготовленных экземпляров: 2БананяблокоКоличество изготовленных экземпляров: 2Бананяблоко

Haxe [ править ]

Вот пример в Haxe [1]

class  Fruit  {  private  static  var _instances =  new  Map < String ,  Fruit > (); общедоступное имя переменной (по умолчанию ,  null ): String ; публичная  функция  new ( name : String )  {  this . name  =  name ;  } общедоступная  статическая  функция  getFruitByName ( name : String ): Fruit  {  if  ( ! _instances . exists ( name ))  {  _instances . set ( название ,  новый  Fruit ( название ));  }  return  _instances . получить ( имя );  } общедоступная  статическая  функция  printAllTypes ()  {  trace ([ для ( ключа  в  _instances . keys ())  ключа ]);  } }

Применение

class  Test  {  public  static  function  main  ()  {  var banana =  Fruit . getFruitByName ( "Банан" );  var apple =  Фрукты . getFruitByName ( "Яблоко" );  var banana2 =  Фрукты . getFruitByName ( "Банан" );  след ( банан  ==  банан2 );  // правда. тот же банан  Фрукты . printAllTypes ();  // ["Банан", "Яблоко"]  } }

Java [ править ]

Вот пример на Java .

import  java.util.HashMap ; import  java.util.Map ; import  java.util.Map.Entry ;public  class  Program  { / **  * @param args  * /  public  static  void  main ( String []  args )  {  Fruit . getFruitByTypeName ( FruitType . банан );  Фрукты . showAll ();  Фрукты . getFruitByTypeName ( FruitType . яблоко );  Фрукты . showAll ();  Фрукты . getFruitByTypeName ( FruitType . банан );  Фрукты . показать все();  } }enum  FruitType  {  нет ,  яблоко ,  банан , }class  Fruit  { частная  статическая  карта < FruitType ,  Fruit >  types  =  new  HashMap <> ();  / **  * Использование частного конструктора для принудительного использования фабричного метода.  * @param type  * /  private  Fruit ( тип FruitType  ) { }    / **  * Метод Lazy Factory, получает экземпляр Fruit, связанный с  * определенным типом. При необходимости создает новые экземпляры.  * @param type Любой разрешенный тип фруктов, например APPLE  * @return Экземпляр Fruit, связанный с этим типом.  * /  public  static  Fruit  getFruitByTypeName ( тип FruitType  ) { Fruit fruit ; // Это имеет проблемы с параллелизмом. Здесь чтение типов не синхронизируется, // поэтому типы .put и types.containsKey могут вызываться одновременно. // Не удивляйтесь, если данные будут повреждены. если ( ! типы .        containsKey ( type ))  {  // Ленивая инициализация  fruit  =  new  Fruit ( type );  типы . положить ( вид ,  фрукт );  }  else  {  // Хорошо, сейчас это доступно  fruit  =  types . получить ( тип );  }  вернуть  фрукты ;  }  / **  * Метод Lazy Factory, получает экземпляр Fruit, связанный с  * определенным типом. При необходимости создает новые экземпляры. Использует  шаблон блокировки с двойной проверкой * для использования в средах с высокой степенью параллелизма.  * @param type Любой разрешенный тип фруктов, например APPLE  * @return Экземпляр Fruit, связанный с этим типом.  * /  public  static  Fruit  getFruitByTypeNameHighConcurrentVersion ( FruitType  type )  {  if  ( ! types . containsKey ( type ))  {  synchronized  ( types )  { // Проверяем еще раз после получения блокировки,  //  чтобы убедиться, что экземпляр не был создан тем временем другим потоком if  ( ! Types . ContainsKey ( type ))  {  //  Типы ленивой инициализации . put ( тип ,  новый  Fruit ( тип ));  }  }  }  возвращаемые  типы . получить ( тип );  }  / **  * Отображает все введенные фрукты.  * /  public  static  void  showAll ()  {  if  ( types . size ()  >  0 )  {  Система . из . println ( "Количество созданных экземпляров ="  +  типы . size ());  for  ( Entry < FruitType ,  Fruit >  entry  :  types . entrySet ())  {  String  fruit  =  entry . getKey (). toString ();  Fruit  =  Персонаж . toUpperCase ( fruit . charAt ( 0 ))  +  fruit . подстрока ( 1 );  Система . из . println ( фрукты );  }  Система . из . println ();  }  } }

Выход

Количество сделанных экземпляров = 1БананКоличество сделанных экземпляров = 2БананяблокоКоличество сделанных экземпляров = 2Бананяблоко

JavaScript [ править ]

Вот пример на JavaScript .

var  Fruit  =  ( function ()  {  var  types  =  {};  function  Fruit ()  {}; // подсчитываем собственные свойства в объекте  function  count ( obj )  {  return  Object . ключи ( obj ). длина ;  } var  _static  =  {  getFruit :  function ( type )  {  if  ( typeof  types [ type ]  ==  'undefined' )  {  types [ type ]  =  new  Fruit ;  }  возвращаемые  типы [ тип ];  },  printCurrentTypes :  function  ()  {  console . log ( 'Количество созданных экземпляров:'  +  count ( типы));  for  ( тип var  в типах ) { console . журнал ( тип ); } } };        return  _static ;}) ();Фрукты . getFruit ( 'Яблоко' ); Фрукты . printCurrentTypes (); Фрукты . getFruit ( 'Банан' ); Фрукты . printCurrentTypes (); Фрукты . getFruit ( 'Яблоко' ); Фрукты . printCurrentTypes ();

Выход

Количество изготовленных экземпляров: 1яблокоКоличество изготовленных экземпляров: 2яблокоБананКоличество изготовленных экземпляров: 2яблокоБанан

PHP [ править ]

Вот пример отложенной инициализации в PHP 7.4:

<? php header ( 'Content-Type: text / plain; charset = utf-8' );class  Fruit {  частная  строка  $ type ;  частный  статический  массив  $ types  =  array (); частная  функция  __construct ( строка  $ type )  {  $ this -> type  =  $ type ;  } public  static  function  getFruit ( string  $ type )  {  // Здесь происходит  отложенная инициализация if  ( ! isset ( self :: types [ $ type ]))  {  self :: types [ $ type ]  =  new  Fruit ( $ type );  } return  self :: types [ $ type ];  } общедоступная  статическая  функция  printCurrentTypes () :  void  {  echo  'Количество созданных экземпляров:'  .  count ( self :: types )  .  " \ п " ;  foreach  ( array_keys ( self :: types )  as  $ key )  {  echo  " $ key \ n " ;  }  эхо  " \ п " ;  } }Fruit :: getFruit ( «Яблоко» ); Fruit :: printCurrentTypes ();Fruit :: getFruit ( "Банан" ); Fruit :: printCurrentTypes ();Fruit :: getFruit ( «Яблоко» ); Fruit :: printCurrentTypes ();/ * ВЫВОД:Количество изготовленных экземпляров: 1 AppleКоличество изготовленных экземпляров: 2 яблочного бананаКоличество изготовленных экземпляров: 2 яблочного банана * /

Python [ править ]

Вот пример на Python .

class  Fruit :  def  __init__ ( self ,  item :  str )  ->  None :  self . item  =  предмет class  Fruits :  def  __init__ ( self )  ->  None :  self . items  =  {}  def  get_fruit ( self ,  item :  str )  ->  Fruit :  если  предмет  не  в  себе . предметы :  самостоятельно . items [ item ]  =  Фрукты ( предмет )  вернуть  себя . предметы [ предмет ]если  __name__  ==  "__main__" :  фрукты  =  фрукты ()  печать ( фрукты . get_fruit ( "Яблоко" ))  печать ( фрукты . get_fruit ( "Лайм" ))

Руби [ править ]

Вот пример в Ruby ленивой инициализации токена аутентификации из удаленной службы, такой как Google. Способ кэширования @auth_token также является примером мемоизации .

требуется  класс 'net / http' 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 и параметры определены позже в конце классаb  =  Blogger . новый б . instance_variable_get ( : @auth_token )  # возвращает ноль b . auth_token  # возвращает токен b . instance_variable_get ( : @auth_token )  # возвращает токен

Scala [ править ]

Scala имеет встроенную поддержку отложенного запуска переменных. [2]

 scala >  val  x  =  {  println ( "Привет" );  99  }  Привет  x :  Int  =  99 scala > lazy val y = { println ( "Привет !!" ); 31 } y : Int = < lazy > scala > y Привет !! res2 : Int = 31 scala > y res3 : Int =                          31 год

Smalltalk [ править ]

Вот пример на Smalltalk типичного метода доступа для возврата значения переменной с использованием отложенной инициализации.

 height  ^ height  ifNil: [ height  : =  2.0 ] .

Альтернативный вариант - использовать метод инициализации, который запускается при создании объекта, а затем использовать более простой метод доступа для получения значения.

 инициализировать  высоту  : =  2,0 высота  ^ высота

Обратите внимание, что отложенная инициализация также может использоваться в не объектно-ориентированных языках .

Теоретическая информатика [ править ]

В области теоретической информатики , отложенная инициализация [3] (также называется ленивый массив ) представляет собой метод , чтобы проектировать структуры данных , которые могут работать с памятью , что не нужно быть инициализировано. В частности, предположим, что у нас есть доступ к таблице T из n неинициализированных ячеек памяти (пронумерованных от 1 до n ), и мы хотим назначить m ячеек этого массива, например, мы хотим назначить T [ k i ]: = v i для пары ( k 1 , v 1 ), ..., (k m , v m ), причем все k i различны. Техника отложенной инициализации позволяет нам сделать это всего за O ( m ) операций, вместо того, чтобы тратить O ( m + n ) операций на первоначальную инициализацию всех ячеек массива. Метод состоит в том, чтобы просто выделить таблицу V, в которой хранятся пары ( k i , v i ) в произвольном порядке, и записать для каждого i в ячейку T [ k i ] позицию в V, где хранится ключ k i , оставляя другие ячейкиT не инициализирован. Это можно использовать для обработки запросов следующим образом: когда мы ищем ячейку T [ k ] для некоторого k , мы можем проверить, находится ли k в диапазоне {1, ..., m }: если это не так, тогда T [ k ] не инициализирован. В противном случае мы проверяем V [ T [ k ]] и проверяем, что первая компонента этой пары равна k . Если это не так, то T [ k ] не инициализирован (и случайно попал в диапазон {1, ..., m }). В противном случае мы знаем, что T [k ] действительно является одной из инициализированных ячеек, а соответствующее значение является вторым компонентом пары.

См. Также [ править ]

  • Двойная проверка блокировки
  • Ленивая загрузка
  • Шаблон прокси
  • Шаблон синглтона

Ссылки [ править ]

  1. ^ «Ленивая инициализация - Шаблоны проектирования - Поваренная книга языка программирования Haxe» . 2018-01-11 . Проверено 9 ноября 2018 .
  2. Поллак, Дэвид (25 мая 2009 г.). Начиная с Scala . ISBN 9781430219897.
  3. ^ Морет, BME; Шапиро, HD (1991). Алгоритмы от P до NP, Том 1: Дизайн и эффективность . Бенджамин / Издательство Каммингс. С. 191–192. ISBN 0-8053-8008-6.

Внешние ссылки [ править ]

  • Статья Филиппа Бишопа и Найджела Уоррена « Совет 67 для Java: Ленивое создание экземпляров - балансирование производительности и использования ресурсов»
  • Примеры кода Java
  • Используйте отложенную инициализацию для экономии ресурсов
  • Описание из репозитория портлендских паттернов
  • Ленивая инициализация служб сервера приложений
  • Ленивое наследование в JavaScript
  • Ленивое наследование в C #