- Отложенная инициализация
-
Шаблон проектирования Отложенная (ленивая) инициализация Lazy initialization Описан в Design Patterns Нет
Отложенная (ленивая) инициализация (англ. Lazy initialization). Приём в программировании, когда некоторая ресурсоёмкая операция (создание объекта, вычисление значения) выполняется непосредственно перед тем, как будет использован её результат. Таким образом, инициализация выполняется «по требованию», а не заблаговременно. Аналогичная идея находит применение в самых разных областях: например, компиляция «на лету» и логистическая концепция «Точно в срок».
Частный случай ленивой инициализации — создание объекта в момент обращения к нему — является одним из порождающих шаблонов проектирования. Как правило, он используется в сочетании с такими шаблонами как Фабричный метод, Одиночка и Заместитель.
Содержание
Достоинства
- Инициализация выполняется только в тех случаях, когда она действительно необходима;
- ускоряется начальная инициализация.
Недостатки
- Невозможно явным образом задать порядок инициализации объектов;
- возникает задержка при первом обращении к объекту.
Примеры реализации
Java
Исходный текст на языке Javapublic class SomeObject { static SomeObject singleInstance = null; String msg; private SomeObject() { msg = "Instance of SomeObject have been created."; } public String toString() { return msg; } // Метод возвращает экземпляр SomeObject, при этом он // создаёт его, если тот ещё не существует public static SomeObject getObject() { if (singleInstance == null) { synchronized (SomeObject.class) { if (singleInstance == null) { singleInstance = new SomeObject(); } } } return singleInstance; } } public class Main { private static long totalMemory; // Этот флаг определяет, было ли выполнено вычисление private static boolean isCalc = false; private static long getTotalMemory() { // Определяем значение totalMemory только при первом вызове if (!isCalc) { totalMemory = Runtime.getRuntime().totalMemory() / 1024; isCalc = true; } return totalMemory; } public static void main(String[] args) { // Здесь значение будет вычислено System.out.println("Total amount of memory: " + getTotalMemory() + " KB"); // Здесь будет использовано значение, сохранённое в переменной if (getTotalMemory() > 1024) { System.out.println(SomeObject.getObject()); } } }
C#
Исходный текст на языке C#public class LazyInitialization<T> where T : new() { protected LazyInitialization() { } private static T _instance; public static T Instance { get { if (_instance == null) { lock (typeof(T)) { if (_instance == null) _instance = new T(); } } return _instance; } } } public sealed class BigObject: LazyInitialization<BigObject> { public BigObject() { //Большая работа System.Threading.Thread.Sleep(3000); System.Console.WriteLine("Экземпляр BigObject создан"); } } class Program { static void Main(string[] args) { System.Console.WriteLine("Первое обращение к экземпляру BigObject..."); //создание объекта происходит только при этом обращении к объекту System.Console.WriteLine(BigObject.Instance); System.Console.WriteLine("Второе обращение к экземпляру BigObject..."); System.Console.WriteLine(BigObject.Instance); //окончание программы System.Console.ReadLine(); } }
using System; public class BigObject { private static BigObject instance; private BigObject() { //Большая работа System.Threading.Thread.Sleep(3000); Console.WriteLine("Экземпляр BigObject создан"); } public override string ToString() { return "Обращение к BigObject"; } // Метод возвращает экземпляр BigObject, при этом он // создаёт его, если тот ещё не существует public static BigObject GetInstance() { // для исключения возможности создания двух объектов // при многопоточном приложении if (instance == null) { lock (typeof(BigObject)) { if (instance == null) instance = new BigObject(); } } return instance; } public static void Main() { Console.WriteLine("Первое обращение к экземпляру BigObject..."); //создание объекта происходит только при этом обращении к объекту Console.WriteLine(BigObject.GetInstance()); Console.WriteLine("Второе обращение к экземпляру BigObject..."); Console.WriteLine(BigObject.GetInstance()); //окончание программы Console.ReadLine(); } }
VB.NET
Исходный текст на языке VB.NETPublic Class LazyInitialization(Of T As New) Protected Sub New() End Sub Private Shared _instance As T Public Shared ReadOnly Property Instance() As T Get If _instance Is Nothing Then SyncLock GetType(T) If _instance Is Nothing Then _instance = New T() End If End SyncLock End If Return _instance End Get End Property End Class Public NotInheritable Class BigObject Inherits LazyInitialization(Of BigObject) Public Sub New() 'Большая работа System.Threading.Thread.Sleep(3000) System.Console.WriteLine("Экземпляр BigObject создан") End Sub End Class Class Program Shared Sub Main() System.Console.WriteLine("Первое обращение к экземпляру BigObject...") 'создание объекта происходит только при этом обращении к объекту System.Console.WriteLine(BigObject.Instance) System.Console.WriteLine("Второе обращение к экземпляру BigObject...") System.Console.WriteLine(BigObject.Instance) 'окончание программы System.Console.ReadLine() End Sub End Class
Python
Исходный текст на языке Python#coding: utf-8 from urlparse import urlparse class LazyUrl: parsed_url = None def __init__(self, url): self.url = url def __parse_url(self): print 'only one calculation' self.parsed_url = urlparse(self.url) return self.parsed_url def __get_parsed_url(self): return self.parsed_url or self.__parse_url() def __getattr__(self, *args, **kwargs): url_attr = args[0] return getattr(self.__get_parsed_url(), url_attr) lazy = LazyUrl('http://ya.ru/test/?test=test&var=2') #Вычисление производится только при первом обращении к объекту print lazy.scheme, lazy.netloc, lazy.path, lazy.query, lazy.params, lazy.fragment
PHP
Исходный текст на языке PHP5// Представим URL как объект // by ultimus <ultimus@pisem.net> class LazyURL { protected $_stringUrl, $_proto, $_domain, $_path; /** * Создание экземпляра класса и передача ему строки URL */ function __construct($stringUrl) { $this->_stringUrl = $stringUrl; } /** * Получаем имя протокола при первом обращении и сохраняем его значение */ public function getProtocol() { if (empty($this->_proto)) { $this->_proto = parse_url($this->_stringUrl, 0); } return $this->_proto; } /** * Получаем доменное имя при первом обращении и сохраняем его значение */ public function getDomain() { if (empty($this->_domain)) { $this->_domain = parse_url($this->_stringUrl, 1); } return $this->_domain; } /** * Получаем путь при первом обращении и сохраняем его значение */ public function getPath() { if (empty($this->_path)) { $this->_path = parse_url($this->_stringUrl, 5); } return $this->_path; } } $url = new LazyURL('http://ru.wikipedia.org/wiki/%D0%9E%D1%82%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%B8%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%28%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F%29'); echo $url->getProtocol(); // значение вычислено и сохранено echo "<br>\n"; echo $url->getDomain(); // значение вычислено и сохранено echo "<br>\n"; echo $url->getPath(); // значение вычислено и сохранено echo "<br>\n"; echo "<br>\n"; echo $url->getProtocol(); // получаем уже вычисленное значение echo "<br>\n"; echo $url->getDomain(); // получаем уже вычисленное значение echo "<br>\n"; echo $url->getPath(); // получаем уже вычисленное значение
Ссылки
- Русскоязычные сайты
- Статья о реализации ленивых вычислений на языке C#
- Ленивая загрузка и её виды
- Ленивая загрузка изображений в Wordpress
Шаблоны проектирования Основные Порождающие Абстрактная фабрика • Объектный пул • Одиночка • Отложенная инициализация • Прототип • Строитель • Фабричный метод
Структурные Поведенческие Интерпретатор • Итератор • Команда • Наблюдатель • Посетитель • Посредник • Состояние • Стратегия • Хранитель • Цепочка обязанностей • Шаблонный метод
Блокировка с двойной проверкой • Однопоточное выполнение • Планировщик Для улучшения этой статьи желательно?: - Найти и оформить в виде сносок ссылки на авторитетные источники, подтверждающие написанное.
Категория:- Шаблоны проектирования
Wikimedia Foundation. 2010.