지연된 초기화

**지연된 초기화**, **게으른 초기화**(lazy initialization)은 컴퓨터 프로그래밍에서 객체 생성, 값 계산, 또는 일부 기타 비용이 많이 드는 과정을 처음 필요한 시점까지 지연시키는 기법이다. 즉, 처음 필요할 때까지 객체 생성, 값 계산 또는 기타 비용이 많이 드는 프로세스를 지연시키는 전술이다. 이는 특히 개체나 기타 리소스의 인스턴스화를 참조하는 일종의 지연 평가이다.

이는 일반적으로 접근자 메서드(또는 속성 getter)를 확장하여 캐시 역할을 하는 전용 멤버가 이미 초기화되었는지 확인함으로써 수행된다. 초기화가 되었다면 즉시 반환된다. 그렇지 않은 경우 새 인스턴스가 생성되어 멤버 변수에 배치되고 처음 사용하기 위해 적시에 호출자에게 반환된다.

개체에 거의 사용되지 않는 속성이 있는 경우 시작 속도가 향상될 수 있다. 평균 평균 프로그램 성능은 메모리(조건 변수의 경우) 및 실행 주기(확인용) 측면에서 약간 더 나쁠 수 있지만 객체 인스턴스화의 영향은 시스템의 시작 단계에 집중되지 않고 시간에 따라 분산되므로 중앙 응답 시간이 크게 향상될 수 있다.

다중 스레드 코드에서는 지연 초기화된 개체/상태에 대한 액세스를 동기화하여 경쟁 조건을 방지해야 한다.

## 예시
### 액션스크립트 3

```actionscript
package examples.lazyinstantiation
{
	public class Fruit
	{
		private var _typeName:String;
		private static var instancesByTypeName:Dictionary = new Dictionary();

		public function Fruit(typeName:String):void
		{
			this._typeName = typeName;
		}

		public function get typeName():String
		{
			return _typeName;
		}

		public static function getFruitByTypeName(typeName:String):Fruit
		{
			return instancesByTypeName[typeName] ||= new Fruit(typeName);
		}

		public static function printCurrentTypes():void
		{
			for each (var fruit:Fruit in instancesByTypeName)
			{
				// iterates through each value
				trace(fruit.typeName);
			}
		}
	}
}
```

기본 사용법:

```actionscript
package
{
	import examples.lazyinstantiation;

	public class Main
	{
		public function Main():void
		{
			Fruit.getFruitByTypeName("Banana");
			Fruit.printCurrentTypes();

			Fruit.getFruitByTypeName("Apple");
			Fruit.printCurrentTypes();

			Fruit.getFruitByTypeName("Banana");
			Fruit.printCurrentTypes();
		}
	}
}
```


### C
함수에서:

```c
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>

struct fruit {
    char *name;
    struct fruit *next;
    int number;
    /* Other members */
};

struct fruit *get_fruit(char *name) {
    static struct fruit *fruit_list;
    static int seq;
    struct fruit *f;
    for (f = fruit_list; f; f = f->next)
        if (0 == strcmp(name, f->name))
            return f;
    if (!(f = malloc(sizeof(struct fruit))))
        return NULL;
    if (!(f->name = strdup(name))) {
        free(f);
        return NULL;
    }
    f->number = ++seq;
    f->next = fruit_list;
    fruit_list = f;
    return f;
}

/* Example code */

int main(int argc, char *argv[]) {
    int i;
    struct fruit *f;
    if (argc < 2) {
        fprintf(stderr, "Usage: fruits fruit-name [...]\n");
        exit(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:

```c
#ifndef _FRUIT_INCLUDED_
#define _FRUIT_INCLUDED_

struct fruit {
    char *name;
    struct fruit *next;
    int number;
    /* Other members */
};

struct fruit *get_fruit(char *name);
void print_fruit_list(FILE *file);

#endif /* _FRUIT_INCLUDED_ */
```


fruit.c:

```c
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include "fruit.h"

static struct fruit *fruit_list;
static 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;
    if (!(f = malloc(sizeof(struct fruit))))
        return NULL;
    if (!(f->name = strdup(name))) {
        free(f);
        return NULL;
    }
    f->number = ++seq;
    f->next = fruit_list;
    fruit_list = f;
    return f;
}

void print_fruit_list(FILE *file) {
    struct fruit *f;
    for (f = fruit_list; f; f = f->next)
        fprintf(file, "%4d  %s\n", f->number, f->name);
}
```


main.c:

```c
#include <stdlib.h>
#include <stdio.h>
#include "fruit.h"

int main(int argc, char *argv[]) {
    int i;
    struct fruit *f;
    if (argc < 2) {
        fprintf(stderr, "Usage: fruits fruit-name [...]\n");
        exit(1);
    }
    for (i = 1; i < argc; i++) {
        if ((f = get_fruit(argv[i]))) {
            printf("Fruit %s: number %d\n", argv[i], f->number);
        }
    }
    printf("The following fruits have been generated:\n");
    print_fruit_list(stdout);
    return 0;
}
```

### Haxe
Haxe의 예는 다음과 같다:
```haxe
class Fruit {
  private static var _instances = new Map<String, Fruit>();

  public var name(default, null):String;

  public function new(name:String) {
    this.name = name;
  }

  public static function getFruitByName(name:String):Fruit {
    if (!_instances.exists(name)) {
      _instances.set(name, new Fruit(name));
    }
    return _instances.get(name);
  }

  public static function printAllTypes() {
    trace([for(key in _instances.keys()) key]);
  }
}
```
사용법
```haxe
class Test {
  public static function main () {
    var banana = Fruit.getFruitByName("Banana");
    var apple = Fruit.getFruitByName("Apple");
    var banana2 = Fruit.getFruitByName("Banana");

    trace(banana == banana2); // true. same banana

    Fruit.printAllTypes(); // ["Banana","Apple"]
  }
}
```


## 같이 보기
* 지연된 로딩
* 프록시 패턴
* 싱글턴 패턴
## 각주

## 외부 링크
* Article "Java Tip 67: Lazy instantiation - Balancing performance and resource usage" by Philip Bishop and Nigel Warren
* Java code examples
* Use Lazy Initialization to Conserve Resources
* Description from the Portland Pattern Repository
* Lazy Initialization of Application Server Services
* Lazy Inheritance in JavaScript
* Lazy Inheritance in C#

분류:소프트웨어 디자인 패턴