CS/디자인패턴

[디자인패턴] Flyweight 패턴 (플라이웨이트 패턴)

mabb 2023. 6. 24. 23:49
반응형

▶디자인 패턴 ( Design Pattern)

:프로그램 개발 시 문제 해결을 위하여 빈번히 사용되는 개발자들의 경험, 내적인 축적에 대하여,
GoF(Gang of Four) 라 불리는 4인의 개발자들이 각각을 패턴으로 정의하고 이름을 붙였다.
이를 디자인 패턴 (Design Pattern) 이라고 한다.
 23개의 디자인 패턴을
『Elements of Reusable Object-Oriented Software』
라는 책으로 발간하였다.

Gang of Four 분들은 모두 안경을 썼다.

 

▷디자인 패턴의 용어를 빌리면 서로의 아이디어를 보다 용이하게 비교, 논의할 수 있게 된다.
▷재사용과 기능확장이 쉬운 소프트웨어를 만들기 위한 유익한 기법이 바로 디자인 패턴이다.

 

---------------------------------------------------------
1. Iterator
2. Adapter
3. Template Method
4. Factory Method
5. Singleton
6. Prototype
7. Builder
8. Abstract Factory
9. Bridge
10. Strategy
11. Composite
12. Decorator
13. Visitor
14. Chain of Responsibility
15. Facade
16. Mediator
17. Observer
18. Memento
19. State
20. Flyweight
21. Proxy
22. Command
23. Interpreter
---------------------------------------------------------

▶Flyweight 패턴

"필요한 객체가 이미 있으면 새로 만들지 않기"
"메모리 등 리소스 절감"
"intrinsic과 extrinsic"


-왜 사용하는가
-클래스다이어그램
-각 클래스(인터페이스)의 역할
-Java소스

▶Flyweight 패턴에 대한 이해

-Flyweight는 플라이급을 뜻한다.(가장 낮은 체급)

-인스턴스가 차지하는 메모리가 낮으면 가볍다고 한다.

-공유할 수 있는 인스턴스는 공유해서 불필요하게 새로운 인스턴스를 생성하지 않는 것이 Flyweight패턴이다.

-필요한 인스턴스가 이미 만들어져 있다면 그것을 사용한다.

-만들어 놓은 인스턴스를 보관하는 공간을 pool이라고 칭한다. 예제에서는 HashMap 컬렉션 프레임워크를 이용하여 만들어진 인스턴스를 보관하고 있다.

-인스턴스가 많이 생성되어 메모리를 많이 차지할 우려가 있는 객체를 Flyweight로 하여 리소스를 절약한다.

-Flyweight 인스턴스 생성을 관리해 주는 역할을 FlyweightFactory라고 칭한다.

-클라이언트는 Flyweight의 인스턴스를 직접 new로 얻지 않고 Factory를 통해서 얻는다.

-인스턴스를 공유하기 때문에 해당 인스턴스를 사용하는 여러 곳에 영향을 줄 수 있다.

-여러 장소에 공유가 되기 때문에 어떤 정보를 공유할 것인가 결정하는 것이 필요하다.

-공유하는 정보 = 본질직인 정보, 조건에 따라 변하지 않는 정보 = intrinsic 한 정보라고 표현

-공유하지 않는 정보 = 비본질적인 정보,조건에 따라 변하는 정보 = extrinsic 한 정보라고 표현

-한번 만들어서 pool에 관리되고 있는 인스턴스는 Garbage Collection(GC) 처리가 되지 않는다. 사용하지 않는 인스턴스가 GC되지 않아 메모리에 계속 남아 있을 수 있다. 이 경우 의도적으로 pool의 참조를 없애 Garbage Collection 처리가 되도록하기도 한다.

 

▶왜 사용하는가

메모리, 시간 등 리소스 절감을 위하여 사용하는 패턴이다. 인스턴스가 필요한 경우 이미 만들어져서 pool에 있다면 new로 새롭게 만들지 않는다. new 연산자를 사용하면 메모리를 새롭게 할당받으면서 시간도 소요하게 된다. 공용(공통)으로 사용할 수 있는 부분을 가진 객체는 저장해두었다가 필요할 때 새롭게 만들지 않고 저장한 것을 가져다 쓰는 것이다. 

 

▶클래스다이어그램

Flyweight 패턴의 클래스다이어그램

 

▶각 클래스(인터페이스)의 역할

▷Flyweight 역할 - BigChar.java

Intrinsic 한 정보를 공유하는 객체 역할이다.

▷FlyweightFactory 역할 - BigCharFactory

pool에 Flyweight 인스턴스들을 관리하고 이미 있는 객체인지 판단하여  Flyweight 인스턴스를 생성하는 역할을 한다.

▷Client 역할 - BigString

Flyweight 역할을 만들고 실행하는 역할이다.

▷Main 역할 - Main.java

예제 프로그램을 실행시키는 역할이다.

 

▶Java 소스

*java1.8 이전 버전을 사용하는 교재를 참고 하였습니다.
Java API 문서 등을 참조하여 제네릭을 적용하는 등 소스를 개선할 필요가 있습니다.
(https://docs.oracle.com/en/java/javase/20/docs/api/)

▷Flyweight 역할 - BigChar.java

package main.java.designpattern.flyweight;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BigChar {
    private char charName;
    private String fontData;

    public BigChar(char charName){
        this.charName = charName;
        try{
            BufferedReader reader = new BufferedReader(new FileReader("big"+charName+".txt"));
            String line;
            StringBuffer buf = new StringBuffer();
            while((line = reader.readLine()) != null){
                buf.append(line);
                buf.append("\n");
            }
            reader.close();
            this.fontData = buf.toString();
        }catch (IOException e){
            this.fontData = charName + "?";
        }
    }
    public void print(){
        System.out.println(fontData);
    }
}

 

▷FlyweightFactory 역할 - BigCharFactory

package main.java.designpattern.flyweight;

import java.util.HashMap;
import java.util.Map;

public class BigCharFactory {
    private static BigCharFactory bigCharFactory = new BigCharFactory();
    private Map<Object,BigChar> pool = new HashMap<>();
    private BigCharFactory(){}
    public static BigCharFactory getInstance(){
        return bigCharFactory;
    }
    public synchronized  BigChar  getBigChar(char charName){
        BigChar bigChar = pool.get("" + charName);
        if(bigChar == null){
            bigChar = new BigChar(charName);
            pool.put("" + charName,bigChar);
        }else{
        }
        return bigChar;
    }
}

 

▷Client 역할 - BigString

package main.java.designpattern.flyweight;

public class BigString {
    private BigChar[] bigChars;
    public BigString(String string){
            initShared(string);
    }
    public BigString(String string ,boolean shared){
        if(shared){
            initShared(string);
        }else{
            initUnShared(string);
        }
    }
    private void initShared(String string){
        bigChars = new BigChar[string.length()];
        BigCharFactory factory = BigCharFactory.getInstance();
        for(int i=0; i<bigChars.length; i++){
            bigChars[i] = factory.getBigChar(string.charAt(i));
        }
    }
    private void initUnShared(String string){
        bigChars = new BigChar[string.length()];
        BigCharFactory factory = BigCharFactory.getInstance();
        for(int i=0; i<bigChars.length; i++){
            bigChars[i] = new BigChar(string.charAt(i));
        }
    }

    public void print(){
        for(int i=0; i<bigChars.length; i++){
            bigChars[i].print();
        }
    }
}

 

▷Main 역할 - Main.java

package main.java.designpattern.flyweight;

import java.util.*;

public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        System.out.println("숫자열을 입력해주세요.");
        String input = sc.nextLine();

        BigString bs;
        bs = new BigString(input,true);
        bs.print();

        bs = new BigString(input, false);
        bs.print();


    }
}

 

 

---------------------------------------------------------
※참고자료
-Java언어로 배우는 디자인 패턴 입문
-Headfirst Design Pattern
-나무위키, 위키백과, 네이버백과
-리팩토링구루(https://refactoring.guru/ko)

반응형