목차
1. Flyweight 패턴이란?
Flyweight 패턴은 객체 지향 디자인 패턴 중 하나로, 메모리 절약과 성능 최적화를 위해 사용됩니다. 주로 동일한 데이터를 여러 객체에서 공유하여, 객체를 많이 생성해야 할 때 메모리 사용을 최소화하고 성능을 향상시키는 데 유용합니다.
이 패턴의 핵심 아이디어는 공유 가능한 객체를 이용하여 메모리를 절약하는 것입니다. Flyweight 패턴은 여러 객체가 공통된 속성을 공유하도록 하여, 메모리 사용량을 줄이고 성능을 최적화합니다.
2. Flyweight 패턴의 구조
Flyweight 패턴은 주로 다음과 같은 구조로 이루어집니다:
- Flyweight Interface: 공유할 수 있는 객체가 구현해야 하는 인터페이스입니다. 객체 간에 외부 상태를 전달받아 처리하는 메서드들을 정의합니다.
- ConcreteFlyweight: 실제로 공유될 수 있는 객체입니다. 내부 상태를 저장하며, 여러 객체들이 동일한 데이터를 공유하도록 관리합니다.
- FlyweightFactory: Flyweight 객체를 생성하고 관리하는 역할을 합니다. 동일한 객체가 여러 번 생성되지 않도록 객체를 재사용하거나 새로운 객체를 생성하여 반환합니다.
- Client: Flyweight 객체를 사용하는 코드입니다. 객체를 필요할 때마다 FlyweightFactory를 통해 얻고, 필요한 외부 상태를 전달하여 객체를 사용합니다.
3. Flyweight 패턴의 주요 개념
Flyweight 패턴에서는 두 가지 주요 상태를 구분합니다:
- 내부 상태 (Intrinsic State): 공유 가능한 객체의 속성입니다. 객체가 생성될 때 변하지 않는 상태로, 여러 객체가 동일하게 공유합니다.
- 외부 상태 (Extrinsic State): 객체에 따라 달라지는 상태입니다. 각 객체마다 다를 수 있으며, 외부에서 관리됩니다.
4. Flyweight 패턴 예시
예시 1: 온라인 게임 아이템 공유
온라인 게임에서 여러 캐릭터들이 동일한 아이템을 사용할 때 Flyweight 패턴을 활용할 수 있습니다. 각 캐릭터가 동일한 아이템을 가질 때, Flyweight 패턴을 사용하면 아이템 객체를 공유하여 메모리를 절약할 수 있습니다.
- 내부 상태 (Intrinsic State): 아이템의 고유 속성 (예: 아이템 이름, 아이템 속성 등)
- 외부 상태 (Extrinsic State): 각 캐릭터가 아이템을 사용하는 상태 (예: 각 캐릭터에 적용된 아이템 효과 등)
// Flyweight 인터페이스
interface Item {
void apply(Character character);
}
// ConcreteFlyweight (공유되는 아이템)
class Sword implements Item {
private String name = "Sword";
private int attackPower = 10;
@Override
public void apply(Character character) {
character.attack(attackPower);
System.out.println(character.getName() + " has equipped a " + name + " with " + attackPower + " attack power.");
}
}
// FlyweightFactory (아이템 객체 관리)
class ItemFactory {
private Map<String, Item> items = new HashMap<>();
public Item getItem(String itemName) {
Item item = items.get(itemName);
if (item == null) {
if ("Sword".equals(itemName)) {
item = new Sword();
}
items.put(itemName, item);
}
return item;
}
}
// Client (캐릭터들)
class Character {
private String name;
private Item equippedItem;
public Character(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void equipItem(Item item) {
this.equippedItem = item;
}
public void attack(int attackPower) {
System.out.println(name + " attacks with " + attackPower + " power!");
}
}
// 게임 캐릭터들
public class Game {
public static void main(String[] args) {
ItemFactory itemFactory = new ItemFactory();
Character character1 = new Character("Warrior");
Character character2 = new Character("Knight");
// 동일한 아이템을 공유하여 메모리 절약
Item sword = itemFactory.getItem("Sword");
character1.equipItem(sword);
character2.equipItem(sword);
character1.equippedItem.apply(character1);
character2.equippedItem.apply(character2);
}
}
이 예시에서, Sword 객체는 두 캐릭터가 공유하며, 각 캐릭터는 외부 상태인 공격력을 다르게 적용받습니다. ItemFactory는 아이템 객체들을 관리하며, 동일한 아이템이 중복 생성되지 않도록 처리합니다.
예시 2: 텍스트 편집기에서 글꼴 공유
문서 편집기에서 여러 텍스트 객체가 동일한 글꼴을 사용할 때 Flyweight 패턴을 활용할 수 있습니다. 글꼴 속성은 변하지 않기 때문에 이를 공유하고, 텍스트의 내용이나 크기 등의 외부 상태만 다르게 처리합니다.
// Flyweight 인터페이스
interface TextStyle {
void apply(String text);
}
// ConcreteFlyweight (공유되는 글꼴)
class Font implements TextStyle {
private String fontName;
public Font(String fontName) {
this.fontName = fontName;
}
@Override
public void apply(String text) {
System.out.println("Applying " + fontName + " font to text: " + text);
}
}
// FlyweightFactory (글꼴 객체 관리)
class TextStyleFactory {
private Map<String, TextStyle> fonts = new HashMap<>();
public TextStyle getFont(String fontName) {
TextStyle font = fonts.get(fontName);
if (font == null) {
font = new Font(fontName);
fonts.put(fontName, font);
}
return font;
}
}
// Client (텍스트 객체)
class Text {
private String content;
private TextStyle font;
public Text(String content) {
this.content = content;
}
public void setFont(TextStyle font) {
this.font = font;
}
public void display() {
font.apply(content);
}
}
// 텍스트 객체들
public class TextEditor {
public static void main(String[] args) {
TextStyleFactory factory = new TextStyleFactory();
Text text1 = new Text("Hello, World!");
Text text2 = new Text("Flyweight Pattern Example!");
// 동일한 글꼴 객체를 공유하여 메모리 절약
TextStyle font = factory.getFont("Arial");
text1.setFont(font);
text2.setFont(font);
text1.display();
text2.display();
}
}
이 예시에서 Font 객체는 여러 텍스트 객체들이 공유하며, 각 텍스트 객체는 외부 상태인 내용만 다르게 처리됩니다. TextStyleFactory는 글꼴 객체들을 관리하며, 중복된 글꼴 객체가 생성되지 않도록 합니다.
5. Flyweight 패턴의 장점
- 메모리 절약: 동일한 속성을 공유하는 객체들을 재사용함으로써 메모리 사용을 줄일 수 있습니다.
- 성능 최적화: 객체 생성 비용을 줄여 시스템의 성능을 향상시킬 수 있습니다.
- 유지보수 용이: 공유되는 객체의 상태를 중앙에서 관리할 수 있어 유지보수가 용이합니다.
6. Flyweight 패턴의 단점
- 복잡성 증가: 객체의 상태를 외부에서 관리해야 하므로 설계가 복잡해질 수 있습니다.
- 외부 상태 관리: 객체 상태를 외부에서 별도로 관리해야 하므로, 관리가 어려운 상황이 발생할 수 있습니다.
7. Flyweight 패턴의 활용 예시
Flyweight 패턴은 대량의 객체를 생성해야 하는 상황에서 유용하게 사용될 수 있습니다. 대표적인 활용 예시는 다음과 같습니다:
- 문서 편집기: 같은 글꼴을 사용하는 텍스트 객체들을 공유하여 메모리를 절약합니다.
- 그래픽 프로그램: 동일한 색상이나 이미지를 사용하는 객체들을 공유하여 메모리 사용을 최소화합니다.
- 게임 개발: 동일한 배경, 아이템, 적 등을 공유하여 성능을 개선하고 메모리를 절약할 수 있습니다.
8. 결론
Flyweight 패턴은 대규모 시스템에서 메모리 사용을 최적화하고 성능을 향상시키기 위해 사용되는 디자인 패턴입니다. 객체를 많이 생성해야 하는 시스템에서 유용하며, 객체 간 공유 가능한 상태를 효율적으로 관리할 수 있습니다. 그러나 설계가 복잡할 수 있으므로 상황에 맞게 신중하게 사용해야 합니다.
'Design Pattern with Java' 카테고리의 다른 글
7. 데코레이터 패턴 (Decorator Pattern) (2) | 2025.01.17 |
---|---|
6. 전략 패턴(Strategy Pattern) (0) | 2025.01.15 |
5. 템플릿메소드 패턴(Template Method) (0) | 2025.01.15 |
4. Builder 패턴(from effective-java) (0) | 2025.01.07 |
4. builder 패턴(gof) (0) | 2025.01.07 |