디자인패턴 - Flyweight
develop/java patterns 2008/06/18 00:00
Flyweight 패턴은 작은 크기의 객체들을 효과적으로 사용하는 방법으로 객체를 공유한다라고 정의한다.
여기서 중요한 것은 공유라는 점이다. 이 이유로 인해 Flyweight 패턴을 사용하면 이름처럼 경량 구조를 제공할 수 있게 된다.
그럼 어떻게 객체를 공유하는 지 살펴본다.

위 그림에서 Client 가 가지고자 하는 객체는 Flyweight의 구상 클래스이다. 이를 FlyweightFactory 를 통해 공급받는 형태가 된다. 형태만으로는 FactoryMethod 나 AbstractFactory 와의 차이를 말하기 힘들다.
FlyweightFactory 는 내부에 flyweight 에 대한 객체 인스턴스를 가지고 있다.
그리고 getFlyweight 메소드를 통해 키에 대한 flyweight 인스턴스를 반환한다.
다시말하면 객체의 인스턴스를 미리 생성시켜 두고, 특정 키를 사용해 접근할 수 있도록 한 구조이다.
여기서 중요한 포인트가 있다.
FlyweightFactory 내부에 저장된 인스턴스는 [develop/java patterns] - 디자인패턴 - Singleton 의 특성을 가진다는 점이다. 그렇게 때문에 Flyweight 패턴의 특성을 알기 위해서는 반드시 Singleton 패턴의 특성을 숙지해야 한다. 이러한 연유로 Registry Singleton 이라 표현하기도 하는데 특정 공간에 Singleton 인스턴스를 모아두고 key를 통해 접근한다는 의미이다. 이를 두고 생성된 인스턴스를 공유한다라고 말하는 것이다.
또 Multi-Thread Model 이라는 말도 Singleton 특성을 표현하는 말 중 하나이다.
앞서 [develop/java patterns] - 디자인패턴 - AbstractFactory 에서 다루었던 스타크래프트 팩토리 예제에 Flyweight 를 입혀본다.
위 그림이 스타크래프트의 팩토리 예제의 완성된 형태이다.
Unit 은 Singleton 이 될 수 없지만, Creator 는 Gingleton 이 될 수 있기에 Creator 가 Flyweight 가 될 수 있다.
그렇게 해서 AbstracFactory 의 메소드는 flyweight 형태인 id 호출로 바뀌면서 가변성을 확보할 수 있게 된다.
FactoryMethod, AbstractFactory, Flyweight 패턴을 함께 묶어 사용하는 것이 객체를 생성해서 제공하는 형태의 종합 선물 세트라 할 수 있다.
[develop/java patterns] - 디자인패턴 - AbstractFactory의 예제 소스에서 살짝 수정을 해본다.
먼저 앞서 AbstractFactory 역할을 하는 Building 을 인터페이스 에서 AbstractClass 로 바꾸었다.
Building 에 대한 구상 클래스인 Factory 와 Barrack 도 수정한다.
이렇게 해서 새로운 유닛과 빌딩을 추가할때 크게 어려움 없이 확장이 가능해진다.
이 예제에서는 Flyweight 의 registry 구성을 각 Building(Factory,Barrack) 의 Constructor 에서 했는데 이를 설정 파일등에서 읽어오도록 한다면, 기존 소스는 변화없이 Factory 에 Unit을 추가하는 등의 처리가 가능해 질 것이다.
위의 그림에서 보면 IntercepterCreator 란 놈이 있는데 , 이것은 공유되지 않는 Creator 란 의미를 설명하고자 삽입한 것이다. Creator(Flyweight) 의 구상 클래스가 반드시 공유되지 않을 수도 있다는 의미를 담고 있다.
별도로 사용하는 경우도 있을 것이고, 또 다른 이유로 인해 그렇게 될 수 밖에 없는 경우도 있다.
Flyweight 패턴의 대표적인 사용예는 Servlet 이다.

우리는 HttpSevlet 을 상속하여 doGet, doPost... 등의 메소드를 override 하는 식으로 서블릿을 만들게 된다.
그리고 SeveltContext API 를 살펴보면 getServlet(String name), getServiceNames() 등 Servlet Registry 역할을 하는 메소드들(지금은 보안 및 여러 사유들로 depercated 되어 있지만)을 볼 수 있다.
그리고 이들 Servlet 들은 기본적으로 Multi Thread Model 로 동작한다.
만일 만든 Servlet 을 Multi Thread Model 로 동작시키고 싶지 않다면, 다음 처럼 하기만 하면 된다.
하지만 SingleThreadModel 은 서버의 성능을 떨어뜨리기 때문에 가급적이면 사용하지 않는 것이 좋다.
그럼, 우리가 만든 Servlet 은 어떻게 ServletContext 에 적재될까...?
이를 위해 Servlet 표준에서는 web.xml 파일이라는 설정 파일을 이용한다.
내가 구현한 luciole.MyServlet 이란 놈을 myServlet 이란 이름으로 ServletContext 에 등록하라는 의미이다.
그리고 URL에 /serv/myServlet 이 들어오면 myServlet 이란 이름으로 되어 있는 Servlet 을 실행시킨다는 의미가 된다.
ServletContext 는 엔진 기동시에 web.xml 을 읽어 들여 각 Servlet 들을 ServletContext 에 등록한다.
그리고 이후 URL 호출에 의해 등록된 Servlet 의 doServlce 를 실행하는 것이다.
MultiThreadModel 에서는 반드시 주의해야 할 점이 있다.
Servlet 사용시 Servlet Life Cycle 이란 말을 들어 본 적이 있는지....
Servlet 이 MultiThreadModel 로 동작되기 때문에 언제 init 되고, 언제 destory 되는지를 알려주기 위한 토픽이다.
이것은 Servlet 의 멤버 변수 사용에 대해 주의할 점이다.
이 Servlet 을 브라우져를 통해 계속 실행시켜 보면... count 값이 계속 증가하는 것을 볼 수 있을 것이다.
이는 MyServlet 인스탄스가 하나만을 계속 떠 있고, 요청이 있을시 doGet 만 수행하기 때문이다.
만일 MultiTrheadModel 이 아니라면 count 는 1만 출력될 것이다.
이해가 안된다면 Servlet Life Cycle 이란 토픽을 검색해서 공부하길 바란다.
멤버 변수는 모든 Thread 가 공유한다는 점을 모른다면, 큰 사고를 낼 수도 있다.
예전에 개발자가 멤버 변수에 로그인한 사람의 주민번호를 넣어두고 사용해서, 로그인 사람이 아닌 다른 사람의 정보를 볼 수 있어서 큰 문제가 되었던 사례를 있었다.
Flyweight 는 리소스 절약이라는 특별한 장점을 가지고 있고, 또 AbstractFactory, FactoryMethod 등과 같이 사용할 경우에 시너지가 크게 나타나기 때문에 프레임워크에서 많이 사용되고 있다.
프레임워크 자료에 경량구조라던지, 외부 설정에서 제어가 가능한 선언적 제어 스타일 이란 말들은 Flyweight 패턴으로 얻어지는 장점에 해당한다.
하지만 단점도 역시 존재하는데....
객체가 물리적으로 직접 연결되지 않기 때문에 역공학 엔진등에서 영향도를 분석하지 못한다.
우리나라의 경우 클래스다이어그램 같은 문서도 역공한 엔진을 돌려서 뽑아내서 제출하는 경우가 종종 있는데,
Flyweight 패턴은 역공학 엔진에서 그 관계가 나타나지 않는다. 또 소스를 따라 다니며 분석을 하는 경우에도 따라다니기가 힘들다. 이클립스에서 제공하는 F3 키도 이 경우는 무용지물이 되니까....
그래서 한때는 다음처럼 키로 Class 객체를 사용하기도 했었는데...
또 어떤 때는 반환 타입을 Object 로 해버려서 다운 캐스팅을 통한 사용을 유도한 경우도 있다.
디자인패턴을 적용하는 의미가 무색해 버리기는 하지만,
실제 개발 및 운영 환경에 따라 가장 편하게 적용하는 것도 무시할 수 없었기 때문인데...
Flyweight 패턴에서 키와 실제 객체의 연관성을 물리적으로 가능하도록 하는 방법은 더 생각해 볼 문제이다.
김평종님의 질문을 받고 내용을 추가해 봅니다.
좀 더 FlyWeight 의 특징을 나타낼 수 있도록 CreatorContext 란 객체를 만들어 보았습니다..
이제 순서대로 Building, Factory, Barrack 을 수정해 보겠습니다.
이렇게 됩니다. MarineCreator 를 보면 최초 한번만 new MarineCreator() 되고,
Barrack 이 몇개가 되건... 한번 생성해 놓은 MarineCreator 인스턴스의 createUnit() 메소드만 수행하게 됩니다.
CreatorContext 를 다음과 같은 XML을 읽어들이도록 한다면... 프로그램은 건들지 않고, 외부 제어가 용이해 지겠죠..
이 예로 조금 더 이해가 되셨으면 좋겠습니다.
여기서 중요한 것은 공유라는 점이다. 이 이유로 인해 Flyweight 패턴을 사용하면 이름처럼 경량 구조를 제공할 수 있게 된다.
그럼 어떻게 객체를 공유하는 지 살펴본다.
위 그림에서 Client 가 가지고자 하는 객체는 Flyweight의 구상 클래스이다. 이를 FlyweightFactory 를 통해 공급받는 형태가 된다. 형태만으로는 FactoryMethod 나 AbstractFactory 와의 차이를 말하기 힘들다.
FlyweightFactory 는 내부에 flyweight 에 대한 객체 인스턴스를 가지고 있다.
그리고 getFlyweight 메소드를 통해 키에 대한 flyweight 인스턴스를 반환한다.
다시말하면 객체의 인스턴스를 미리 생성시켜 두고, 특정 키를 사용해 접근할 수 있도록 한 구조이다.
여기서 중요한 포인트가 있다.
FlyweightFactory 내부에 저장된 인스턴스는 [develop/java patterns] - 디자인패턴 - Singleton 의 특성을 가진다는 점이다. 그렇게 때문에 Flyweight 패턴의 특성을 알기 위해서는 반드시 Singleton 패턴의 특성을 숙지해야 한다. 이러한 연유로 Registry Singleton 이라 표현하기도 하는데 특정 공간에 Singleton 인스턴스를 모아두고 key를 통해 접근한다는 의미이다. 이를 두고 생성된 인스턴스를 공유한다라고 말하는 것이다.
또 Multi-Thread Model 이라는 말도 Singleton 특성을 표현하는 말 중 하나이다.
앞서 [develop/java patterns] - 디자인패턴 - AbstractFactory 에서 다루었던 스타크래프트 팩토리 예제에 Flyweight 를 입혀본다.
Unit 은 Singleton 이 될 수 없지만, Creator 는 Gingleton 이 될 수 있기에 Creator 가 Flyweight 가 될 수 있다.
그렇게 해서 AbstracFactory 의 메소드는 flyweight 형태인 id 호출로 바뀌면서 가변성을 확보할 수 있게 된다.
FactoryMethod, AbstractFactory, Flyweight 패턴을 함께 묶어 사용하는 것이 객체를 생성해서 제공하는 형태의 종합 선물 세트라 할 수 있다.
[develop/java patterns] - 디자인패턴 - AbstractFactory의 예제 소스에서 살짝 수정을 해본다.
먼저 앞서 AbstractFactory 역할을 하는 Building 을 인터페이스 에서 AbstractClass 로 바꾸었다.
public abstract class Building {
protected HashMap creators;
protected Building() {
this.creators = new HashMap();
}
protected Unit createUnit(String key) {
return ((Creator)this.creators.get(key)).createUnit();
}
protected void putUnit(String key, Creator creator) {
this.creators.put(key,creator);
}
public abstract Unit command1();
public abstract Unit command2();
}
java.util.HashMap 을 사용해 Registry 를 만들었고 createUnit 메소드로 키에 대한 Unit 을 생성하여 반환한다.protected HashMap creators;
protected Building() {
this.creators = new HashMap();
}
protected Unit createUnit(String key) {
return ((Creator)this.creators.get(key)).createUnit();
}
protected void putUnit(String key, Creator creator) {
this.creators.put(key,creator);
}
public abstract Unit command1();
public abstract Unit command2();
}
Building 에 대한 구상 클래스인 Factory 와 Barrack 도 수정한다.
public class Factory extends Building {
public Factory() {
super();
putUnit("1", new SiegeTankCreator()); // SiegeTankCreator 등록
putUnit("2", new VultureCreator()); // VultureCreator 등록
}
public Unit command1() { return createUnit("1"); }
public Unit command2() { return createUnit("2"); }
}
public Factory() {
super();
putUnit("1", new SiegeTankCreator()); // SiegeTankCreator 등록
putUnit("2", new VultureCreator()); // VultureCreator 등록
}
public Unit command1() { return createUnit("1"); }
public Unit command2() { return createUnit("2"); }
}
public class Barrack extends Building {
public Barrack() {
super();
putUnit("Marine", new MarineCreator()); // MarineCreator 등록
putUnit("Medic", new MedicCreator()); // MedicCreator 등록
}
public Unit command1() { return createUnit("Marine"); }
public Unit command2() { return createUnit("Medic"); }
}
이렇게 AbstractFactory 패턴에 Flyweight 패턴을 더해서 구성했고, 실행 결과는 앞서와 동일하다.public Barrack() {
super();
putUnit("Marine", new MarineCreator()); // MarineCreator 등록
putUnit("Medic", new MedicCreator()); // MedicCreator 등록
}
public Unit command1() { return createUnit("Marine"); }
public Unit command2() { return createUnit("Medic"); }
}
이렇게 해서 새로운 유닛과 빌딩을 추가할때 크게 어려움 없이 확장이 가능해진다.
이 예제에서는 Flyweight 의 registry 구성을 각 Building(Factory,Barrack) 의 Constructor 에서 했는데 이를 설정 파일등에서 읽어오도록 한다면, 기존 소스는 변화없이 Factory 에 Unit을 추가하는 등의 처리가 가능해 질 것이다.
위의 그림에서 보면 IntercepterCreator 란 놈이 있는데 , 이것은 공유되지 않는 Creator 란 의미를 설명하고자 삽입한 것이다. Creator(Flyweight) 의 구상 클래스가 반드시 공유되지 않을 수도 있다는 의미를 담고 있다.
별도로 사용하는 경우도 있을 것이고, 또 다른 이유로 인해 그렇게 될 수 밖에 없는 경우도 있다.
Flyweight 패턴의 대표적인 사용예는 Servlet 이다.
우리는 HttpSevlet 을 상속하여 doGet, doPost... 등의 메소드를 override 하는 식으로 서블릿을 만들게 된다.
그리고 SeveltContext API 를 살펴보면 getServlet(String name), getServiceNames() 등 Servlet Registry 역할을 하는 메소드들(지금은 보안 및 여러 사유들로 depercated 되어 있지만)을 볼 수 있다.
그리고 이들 Servlet 들은 기본적으로 Multi Thread Model 로 동작한다.
만일 만든 Servlet 을 Multi Thread Model 로 동작시키고 싶지 않다면, 다음 처럼 하기만 하면 된다.
extends HttpServlet implements SingleThreadModel
이렇게 하면 ServletContext 는 이 서블릿을 레지스트리에 담아 두지 않고, 호출시 마다 인스턴스를 생성하고 수행을 마치면 가비지로 되게 한다. 즉 이 서블릿 인스턴스는 공유되지 않는다라는 의미다. 하지만 SingleThreadModel 은 서버의 성능을 떨어뜨리기 때문에 가급적이면 사용하지 않는 것이 좋다.
그럼, 우리가 만든 Servlet 은 어떻게 ServletContext 에 적재될까...?
이를 위해 Servlet 표준에서는 web.xml 파일이라는 설정 파일을 이용한다.
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>luciole.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/serv/myServlet</url-pattern>
</servlet-mapping>
web.xml 을 위와 같이 사용하는 것은<servlet-name>myServlet</servlet-name>
<servlet-class>luciole.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/serv/myServlet</url-pattern>
</servlet-mapping>
내가 구현한 luciole.MyServlet 이란 놈을 myServlet 이란 이름으로 ServletContext 에 등록하라는 의미이다.
그리고 URL에 /serv/myServlet 이 들어오면 myServlet 이란 이름으로 되어 있는 Servlet 을 실행시킨다는 의미가 된다.
ServletContext 는 엔진 기동시에 web.xml 을 읽어 들여 각 Servlet 들을 ServletContext 에 등록한다.
그리고 이후 URL 호출에 의해 등록된 Servlet 의 doServlce 를 실행하는 것이다.
MultiThreadModel 에서는 반드시 주의해야 할 점이 있다.
Servlet 사용시 Servlet Life Cycle 이란 말을 들어 본 적이 있는지....
Servlet 이 MultiThreadModel 로 동작되기 때문에 언제 init 되고, 언제 destory 되는지를 알려주기 위한 토픽이다.
이것은 Servlet 의 멤버 변수 사용에 대해 주의할 점이다.
public class MyServlet extends HttpServlet {
private int count = 0;
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException,ServletException {
count++;
res.getWriter().println("count : " + count);
}
}
MyServlet 은 count 라는 멤버 변수를 두고 있고, deGet 에서 1을 증가시키고 그 값을 출력하도록 되어 있다.private int count = 0;
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException,ServletException {
count++;
res.getWriter().println("count : " + count);
}
}
이 Servlet 을 브라우져를 통해 계속 실행시켜 보면... count 값이 계속 증가하는 것을 볼 수 있을 것이다.
이는 MyServlet 인스탄스가 하나만을 계속 떠 있고, 요청이 있을시 doGet 만 수행하기 때문이다.
만일 MultiTrheadModel 이 아니라면 count 는 1만 출력될 것이다.
이해가 안된다면 Servlet Life Cycle 이란 토픽을 검색해서 공부하길 바란다.
멤버 변수는 모든 Thread 가 공유한다는 점을 모른다면, 큰 사고를 낼 수도 있다.
예전에 개발자가 멤버 변수에 로그인한 사람의 주민번호를 넣어두고 사용해서, 로그인 사람이 아닌 다른 사람의 정보를 볼 수 있어서 큰 문제가 되었던 사례를 있었다.
Flyweight 는 리소스 절약이라는 특별한 장점을 가지고 있고, 또 AbstractFactory, FactoryMethod 등과 같이 사용할 경우에 시너지가 크게 나타나기 때문에 프레임워크에서 많이 사용되고 있다.
프레임워크 자료에 경량구조라던지, 외부 설정에서 제어가 가능한 선언적 제어 스타일 이란 말들은 Flyweight 패턴으로 얻어지는 장점에 해당한다.
하지만 단점도 역시 존재하는데....
객체가 물리적으로 직접 연결되지 않기 때문에 역공학 엔진등에서 영향도를 분석하지 못한다.
우리나라의 경우 클래스다이어그램 같은 문서도 역공한 엔진을 돌려서 뽑아내서 제출하는 경우가 종종 있는데,
Flyweight 패턴은 역공학 엔진에서 그 관계가 나타나지 않는다. 또 소스를 따라 다니며 분석을 하는 경우에도 따라다니기가 힘들다. 이클립스에서 제공하는 F3 키도 이 경우는 무용지물이 되니까....
그래서 한때는 다음처럼 키로 Class 객체를 사용하기도 했었는데...
import FlyWeight;
import ConcreteFlyWeight;
public class Client {
public static void main(String[] args) {
Flyweight fw = getFlyweight(ConcreteFlyweight.class);
}
}
이 때는 일단 관계가 물리적으로 드러나긴 하지만, 키와 객체가 1:1 이기 때문에 한 객체를 이키 저키로 재사용할 수 없는 단점이 생기기도 한다. import ConcreteFlyWeight;
public class Client {
public static void main(String[] args) {
Flyweight fw = getFlyweight(ConcreteFlyweight.class);
}
}
또 어떤 때는 반환 타입을 Object 로 해버려서 다운 캐스팅을 통한 사용을 유도한 경우도 있다.
디자인패턴을 적용하는 의미가 무색해 버리기는 하지만,
실제 개발 및 운영 환경에 따라 가장 편하게 적용하는 것도 무시할 수 없었기 때문인데...
Flyweight 패턴에서 키와 실제 객체의 연관성을 물리적으로 가능하도록 하는 방법은 더 생각해 볼 문제이다.
김평종님의 질문을 받고 내용을 추가해 봅니다.
좀 더 FlyWeight 의 특징을 나타낼 수 있도록 CreatorContext 란 객체를 만들어 보았습니다..
public class CreatorContext {
private static final CreatorContext SINGLETON;
public static synchronized CreatorContext getInstance() {
if ( SINGLETON == null ) SINGLETON = new CreatorContext();
return SINGLETON;
}
private HashMap creatorMap;
private CreatorContext() {
this.creatorMap = new HashMap();
this.creatorMap.put("Marine",new MarineCreator() );
this.creatorMap.put("Medic",new MedicCreator() );
this.creatorMap.put("SiegeTank", new SiegeTankCreator() );
this.creatorMap.put("Vulture", new VultureCreator() );
}
public Creator getCreator(String key) {
return (Creator) this.creatorMap.get(key);
}
}
private static final CreatorContext SINGLETON;
public static synchronized CreatorContext getInstance() {
if ( SINGLETON == null ) SINGLETON = new CreatorContext();
return SINGLETON;
}
private HashMap creatorMap;
private CreatorContext() {
this.creatorMap = new HashMap();
this.creatorMap.put("Marine",new MarineCreator() );
this.creatorMap.put("Medic",new MedicCreator() );
this.creatorMap.put("SiegeTank", new SiegeTankCreator() );
this.creatorMap.put("Vulture", new VultureCreator() );
}
public Creator getCreator(String key) {
return (Creator) this.creatorMap.get(key);
}
}
이제 순서대로 Building, Factory, Barrack 을 수정해 보겠습니다.
public abstract class Building {
protected CreatorContext creators;
protected Building() {
this.creators = CreatorContext.getInstance();
}
protected Unit createUnit(String key) {
return this.creators.getCreator(key)).createUnit();
}
public abstract Unit command1();
public abstract Unit command2();
}
protected CreatorContext creators;
protected Building() {
this.creators = CreatorContext.getInstance();
}
protected Unit createUnit(String key) {
return this.creators.getCreator(key)).createUnit();
}
public abstract Unit command1();
public abstract Unit command2();
}
public class Factory extends Building {
public Factory() {
super();
}
public Unit command1() { return createUnit("SiegeTank"); }
public Unit command2() { return createUnit("Vulture"); }
}
public Factory() {
super();
}
public Unit command1() { return createUnit("SiegeTank"); }
public Unit command2() { return createUnit("Vulture"); }
}
public class Barrack extends Building {
public Barrack() {
super();
}
public Unit command1() { return createUnit("Marine"); }
public Unit command2() { return createUnit("Medic"); }
}
public Barrack() {
super();
}
public Unit command1() { return createUnit("Marine"); }
public Unit command2() { return createUnit("Medic"); }
}
이렇게 됩니다. MarineCreator 를 보면 최초 한번만 new MarineCreator() 되고,
Barrack 이 몇개가 되건... 한번 생성해 놓은 MarineCreator 인스턴스의 createUnit() 메소드만 수행하게 됩니다.
CreatorContext 를 다음과 같은 XML을 읽어들이도록 한다면... 프로그램은 건들지 않고, 외부 제어가 용이해 지겠죠..
<Creators>
<Creator key="Marine">MarineCreator</Creator>
<Creator key="Medic">MarineCreator</Creator>
<Creator key="SiegeTank">SiegeTankCreator</Creator>
<Creator key="Vulture">VultureCreator</Creator>
</Creators>
<Creator key="Marine">MarineCreator</Creator>
<Creator key="Medic">MarineCreator</Creator>
<Creator key="SiegeTank">SiegeTankCreator</Creator>
<Creator key="Vulture">VultureCreator</Creator>
</Creators>
이 예로 조금 더 이해가 되셨으면 좋겠습니다.
'develop > java patterns' 카테고리의 다른 글
| 디자인패턴 - TemplateMethod (0) | 2008/06/24 |
|---|---|
| 디자인패턴 연습 5 (0) | 2008/06/18 |
| 디자인패턴 - Flyweight (3) | 2008/06/18 |
| 디자인패턴 연습 5 (0) | 2008/06/18 |
| 디자인패턴 - Singleton (1) | 2008/06/17 |
| 디자인패턴 - AbstractFactory (0) | 2008/06/16 |
-
-
오래된꿈읽기 2008/11/06 15:24
FlyWeight 의 핵심은 한번 생성한 객체를 재사용 한다는 것입니다. 내용중에서도 말한바 있는 Singleton 의 특징을 먼저 이해해야 합니다.
자바에서는 new Object 으로 객체를 생성할때 프로세스 점유율이 높은 것으로 알려져 있고, 또 한번 생성된 후 사용을 마친 객체는 가비지가 됩니다. 자바는 이런 가비지를 가비지컬렉터란 놈이 돌면서 주기적으로 가비지를 메모리에서 해제하게 됩니다. 가비지가 많이 쌓이는 구조라면 가비지 컬렉터가 빈번하게 작동하게 되서 성능 저하의 요소가 됩니다. Singleton 이나 FlyWeight 는 한번 생성한 객체를 가비지로 만들지 않고 계속하여 재사용하게 됩니다.
외부 설정 파일을 통해 putUnit 을 하도록 구성한다면.. 프로그램을 건들지 않고, 설정 파일을 바꿔 Creator 객체를 교체할 수 있을 수 있구요...
예제 소스중에..
new MarineCreator() 하는 부분을 putUnit 으로 바뀌는 부분만이 FlyWeight 패턴이라고 보시면 됩니다.
나머지는 AbstractFactory, FactoryMethod 패턴이구요..
답변이 오히려 더 혼돈이 주는 게 아닌가 모르겠네요..
한번 생성한 객체를 재사용 한다는 핵심이 중요할 것 같습니다. Singleton 을 한번 더 살펴보시구요..
좀 더 이해가 되시도록 내용을 추가해 보겠습니다.
-






