Flyweight Pattern

2021. 12. 11. 19:56Computer Sciences/Design Patterns

개요

Flyweight는 격투기에서 가장 가벼운 몸무게 범주에 속한다. 그렇다면 이 패턴 또한 무언가를 가볍게 처리한다고 미루어 짐작할 수 있다.
Flyweight 패턴은 어떤 클래스의 인스턴스 한 개를 이용하여 가상 인스턴스를 제공하고 싶을 때 사용한다. 예를 들어 스타크래프트를 생각해보자. 마린(해병)은 움직이기, 총 쏘기, 스팀팩 등 모두 공통적인 기능을 사용한다. 이때 200명의 마린 인스턴스를 전부 생성한다고 어떨까? 분명 공통적인 부분은 전혀 변하지 않는다. 그러나 모든 인스턴스가 이를 각자 가지고 메모리에 올라가기 때문에 불필요한 메모리 낭비가 발생한다.
이 패턴을 다시 말하면 어떤 클래스의 공통적인 기능들을 하나의 인스턴스를 공유하도록 하여 메모리를 절약하는 패턴이다. 이제 예제 코드를 살펴보면서 자세히 알아보자.

예제 - 카운터 스트라이크

카운터 스트라이크는 해보신 분들도 있겠지만 테러리스트 팀과 대테러리스트 팀을 이루고 각 팀별로 미션을 클리어하면 승리하는 게임이다. 테러리스트 팀은 폭탄을 설치하고 터뜨리면 승리하고, 대테러리스트팀은 설치된 폭탄을 해체하면 승리한다.  그렇다면 여기서 생각해볼 것은 중복되는 부분과 그렇지 않은 부분이다. 예를 들어 각 팀의 멤버들은 서로 맡은 미션이 모두 같다. 그리고 무기를 소지한다는 점이 같다. 하지만 각자 서로 다른 무기를 사용할 수 있다. 따라서 테러리스트 플레이어 객체와 대테러리스트 플레이어 객체를 하나씩 만들어두고 각 인스턴스에 무기만 설정해주면 모든 멤버에 대한 인스턴스를 생성하지 않아도 게임을 할 수 있다.
여기서 객체를 하나씩 만들어 둔다는 점을 생각해보자. 여기에 대해서는 두 가지 방법이 있다. 싱글턴 패턴과 팩토리 패턴이다. 여기서는 팩토리 패턴을 사용하도록 하겠다.

Class Diagram

코드

// 두 팀의 멤버 모두에게 부여된 공통 부분 추상화
public interface Player {
    void assignWeapon(String weapon);

    void mission();
}
public class Terrorist implements Player {

    private final String TASK;
    private String weapon;

    public Terrorist() {
        TASK = "PLANT A BOMB";
    }

    // 무기는 설정할 수 있도록 setter를 열어 둔다.
    @Override
    public void assignWeapon(String weapon) {
        this.weapon = weapon;
    }

    @Override
    public void mission() {
        System.out.println("Terrorist with weapon " + 
				weapon + " |" + " Task is " + TASK);
    }

}
public class CounterTerrorist implements Player {

    private final String TASK;
    private String weapon;

    public CounterTerrorist() {
        TASK = "DIFFUSE BOMB";
    }

    // 무기는 설정할 수 있도록 setter를 열어 둔다.
    @Override
    public void assignWeapon(String weapon) {
        this.weapon = weapon;
    }

    @Override
    public void mission() {
        System.out.println("Counter Terrorist with weapon " +
				weapon + " |" + " Task is " + TASK);
    }

}
public class PlayerFactory {

    // 멀티 쓰레드 환경이라면 ConcurrentHashMap을 사용하자.
    private static HashMap<String, Player> hm = new HashMap<>();

    // 이미 인스턴스가 존재하면 해당 인스턴스를 반환하고 없으면 생성한다.
    public static Player getPlayer(String type) {
        Player p = null;
        if (hm.containsKey(type)) {
            p = hm.get(type);
        } else {
            switch (type) {
                case "Terrorist":
                    System.out.println("Terrorist created");
                    p = new Terrorist();
                    break;
                case "CounterTerrorist":
                    System.out.println("CounterTerrorist created");
                    p = new CounterTerrorist();
                    break;
                default:
                    System.out.println("Unreachable code!");
            }
            hm.put(type, p);
        }
        return p;
    }
}
public class CounterStrike {

    private static String[] playerType = { "Terrorist", "CounterTerrorist" };
    private static String[] weapons =
			{ "AK-47", "Maverick", "Gut Knife", "Desert Eagle" };

    public static void main(String[] args) {

        for (int i = 0; i < 10; i++) {
            Player player = PlayerFactory.getPlayer(getRandPlayerType());
            player.assignWeapon(getRandWeapon());
            player.mission();
        }
    }

    public static String getRandPlayerType() {
        Random r = new Random();
        int randInt = r.nextInt(playerType.length);
        return playerType[randInt];
    }

    public static String getRandWeapon() {
        Random r = new Random();
        int randInt = r.nextInt(weapons.length);
        return weapons[randInt];
    }
}

장단점

장점

  • 실행 시 인스턴스의 개수를 줄여 메모리를 절약할 수 있다.
  • 여러 가상 객체의 상태를 한 곳에 집중시켜놓을 수 있다.
  • 어떤 클래스의 인스턴스가 아주 많이 필요하지만 모두 똑같은 방식으로 제어할 수 있는 경우에 유용하다.

단점

  • 특정 인스턴스만 다른 행동을 하는 것이 불가능하게 된다. 즉 모든 인스턴스가 동일하게 행동한다.

'Computer Sciences > Design Patterns' 카테고리의 다른 글

Interpreter Pattern  (0) 2021.12.12
Memento Pattern  (0) 2021.12.11
Visitor Pattern  (0) 2021.12.11
Prototype Pattern  (0) 2021.12.11
14. Chain of Responsibility Pattern  (0) 2021.11.14