ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 플라이웨이트 패턴(Flyweight Pattern)이란?
    Design Pattern/구조 디자인 패턴 2024. 4. 14. 16:26
    반응형

     플라이웨이트 패턴(Flyweight Pattern)은 객체 지향 디자인 패턴 중 하나로, 메모리 사용을 최적화하기 위해 공유를 통해 대량의 작은 객체들을 효율적으로 지원합니다. 이 패턴은 반복되는 상태를 공유 객체(플라이웨이트)로 분리하여, 여러 컨텍스트에서 재사용함으로써 메모리 소비를 줄이는 것을 목표로 합니다.

    1. 플라이웨이트 패턴은 주로 어디에 쓰이나?

     플라이웨이트 패턴은 주로 시스템에 많은 수의 객체가 필요할 때 사용되며, 이 객체들이 중복되는 상태를 많이 공유할 수 있을 때 유용합니다. 예를 들어, 텍스트 편집기에서의 문자 객체, 게임에서의 풍경 요소, GUI 툴킷의 그래픽 컴포넌트 등에서 자주 사용됩니다.

    2. Java와 Go로 플라이웨이트 패턴을 구현할 때의 차이점

     Java에서 플라이웨이트 패턴은 클래스와 인터페이스를 사용하여 구현되며, 객체의 공유를 위한 풀을 만드는 것이 일반적입니다. 반면, Go에서는 인터페이스와 구조체를 사용하되, 포인터와 맵을 이용해 객체의 공유를 관리하는 것이 특징입니다. Go의 경우, 내장된 가비지 컬렉션 기능 덕분에 메모리 관리가 더 단순화됩니다.

    3. 플라이웨이트 패턴 예시

    Java 예시 코드:

    import java.util.HashMap;
    import java.util.Map;
    
    interface Flyweight {
        void doOperation(String extrinsicState);
    }
    
    class ConcreteFlyweight implements Flyweight {
        private String intrinsicState;
    
        public ConcreteFlyweight(String intrinsicState) {
            this.intrinsicState = intrinsicState;
        }
    
        @Override
        public void doOperation(String extrinsicState) {
            System.out.println("Intrinsic State = " + intrinsicState + ", Extrinsic State = " + extrinsicState);
        }
    }
    
    class FlyweightFactory {
        private Map<String, Flyweight> flyweights = new HashMap<>();
    
        public Flyweight getFlyweight(String key) {
            if (!flyweights.containsKey(key)) {
                flyweights.put(key, new ConcreteFlyweight(key));
            }
            return flyweights.get(key);
        }
    }
    
    // 사용 예
    public class Main {
        public static void main(String[] args) {
            FlyweightFactory factory = new FlyweightFactory();
            Flyweight fw1 = factory.getFlyweight("State1");
            Flyweight fw2 = factory.getFlyweight("State2");
            fw1.doOperation("Operation1");
            fw2.doOperation("Operation2");
        }
    }

    클래스와 인터페이스:

    • Flyweight: 인터페이스로, 모든 플라이웨이트 객체가 구현해야 하는 doOperation 메서드를 선언합니다. 이 메서드는 외부 상태(extrinsicState)를 인자로 받습니다.
    • ConcreteFlyweight: Flyweight 인터페이스를 구현하는 구체 클래스입니다. 내부 상태(intrinsicState)를 가지고 있으며, 이 상태는 객체 생성 시 초기화됩니다.
    • FlyweightFactory: 플라이웨이트 객체의 생성과 관리를 책임지는 팩토리 클래스입니다. getFlyweight 메서드를 통해 요청받은 키에 해당하는 플라이웨이트 객체를 반환합니다. 객체가 이미 생성되어 있지 않으면 새로 생성하여 저장합니다.

    동작:

    • 메인 함수에서 FlyweightFactory 객체를 생성하고, getFlyweight 메서드를 호출하여 특정 상태의 플라이웨이트 객체를 요청합니다.
    • 각 객체는 고유 상태를 유지하며, 호출 시 외부에서 상태를 전달받아 동작을 수행합니다.

     

    Golang 예시 코드:

    package main
    
    import "fmt"
    
    type Flyweight interface {
        DoOperation(extrinsicState string)
    }
    
    type ConcreteFlyweight struct {
        intrinsicState string
    }
    
    func (f *ConcreteFlyweight) DoOperation(extrinsicState string) {
        fmt.Println("Intrinsic State =", f.intrinsicState, ", Extrinsic State =", extrinsicState)
    }
    
    type FlyweightFactory struct {
        flyweights map[string]Flyweight
    }
    
    func NewFlyweightFactory() *FlyweightFactory {
        return &FlyweightFactory{make(map[string]Flyweight)}
    }
    
    func (f *FlyweightFactory) GetFlyweight(key string) Flyweight {
        if _, ok := f.flyweights[key]; !ok {
            f.flyweights[key] = &ConcreteFlyweight{key}
        }
        return f.flyweights[key]
    }
    
    // 사용 예
    func main() {
        factory := NewFlyweightFactory()
        fw1 := factory.GetFlyweight("State1")
        fw2 := factory.GetFlyweight("State2")
        fw1.DoOperation("Operation1")
        fw2.DoOperation("Operation2")
    }

    인터페이스와 구조체:

    • Flyweight: 인터페이스로, DoOperation 메서드를 정의합니다. 이 메서드는 외부 상태를 인자로 받습니다.
    • ConcreteFlyweight: Flyweight 인터페이스를 구현하는 구조체로, 내부 상태(intrinsicState)를 포함합니다.
    • FlyweightFactory: 플라이웨이트 객체를 생성 및 관리하는 구조체입니다. 맵을 사용하여 생성된 객체를 저장하고, GetFlyweight 메서드를 통해 객체를 제공합니다.

    동작:

    • main 함수에서 NewFlyweightFactory 함수를 호출하여 팩토리를 초기화하고, GetFlyweight 메서드로 특정 상태의 플라이웨이트 객체를 요청합니다.
    • 각 객체는 내부 상태를 유지하고, 호출 시 외부 상태를 전달받아 해당 상태에 따라 동작을 수행합니다.

    Java와 Go의 차이점:

    • Java에서는 클래스 기반의 접근 방식을 사용하는 반면, Go에서는 구조체와 인터페이스를 사용한 더 단순화된 접근 방식을 취합니다.
    • Go의 경우, 내장된 가비지 컬렉션과 간결한 구문 덕분에 메모리 관리와 구현이 더 간단합니다.

    이 예시들을 통해 두 언어에서 플라이웨이트 패턴이 어떻게 다르게 구현되는지 이해할 수 있으며, 메모리 효율성을 높이는 데에 큰 도움이 됩니다.

    4. 플라이웨이트 패턴의 장단점

    장점:

    • 메모리 절약: 대규모 객체 시스템에서 상당한 메모리 절감 효과.
    • 중복 최소화: 공유를 통해 객체의 중복 생성을 방지.

    단점:

    • 코드 복잡성 증가: 객체를 공유하는 방식은 구현을 복잡하게 만듭니다.
    • 런타임 비용: 객체 상태를 관리하는 데 런타임 비용이 발생할 수 있습니다.
    반응형
Designed by Tistory.