사용 의도
- 객체의 공유를 통해, 인스턴스의 생성을 최적화합니다.
예시
- 레이싱 경주에서, 1000대의 자동차를 가지고 경기를합니다.
- 하지만 자동차의 인스턴스의 크기가 매우 크다.
- 자동차를 운전하는 운전수의 인스턴스는 크기가 작다.
- 위의 조건에서 객체의 공유를 통해 인스턴스의 생성을 최적화합니다.
구조
참여자 | 설명 |
Flyweight | Flyweight 클래스들의 추상클래스 혹은 인터페이스입니다. |
ConcreteFlyweight | Flyweight 를 상속받거나 구현한, 공유될 수 있는 객체들입니다. |
UnsharedConcreteFlyweight | Flyweight 를 상속받거나 구현한, 공유하지 않는 객체들입니다. |
FlyweightFactory | Flyweight 를 생성하는 팩토리입니다. Client 가 Flyweight 객체를 요청하면, - 팩토리에 이미 존재하는 경우 : 즉시 반환 - 팩토리에 존재하지 않는 경우 : 생성 후 반환 |
Client | FlyweightFactory 에 객체를 요청하며, 공유하지 않는 개별적인 데이터를 갖고있습니다. |
코드
RaceCar (Flyweight)
- 자동차에 두종류가 있으며, 아래와 같다고 할 때, 이름 / 속력 / 마력은 하나의 공유하는 인스턴스에서 공통적으로 사용하는 데이터입니다.
MidgetCar | SprintCar | |
이름 | Midget | Sprint |
속력 | 140 | 160 |
마력 | 400 | 1000 |
@Getter
@Setter
public abstract class RaceCar {
/**
* Instrinsic (공유하는 객체가 모두 공통적으로 갖고있는 데이터)
*/
private String name;
private int speed;
private int horsePower;
/**
* Extrinsic (외부에서 공통으로 사용하는 메소드)
*/
abstract void moveCar(int currentX, int currentY, int newX, int newY);
}
MidgetCar (ConcreteFlyweight)
public class FlyweightMidgetCar extends RaceCar {
public static int num;
public FlyweightMidgetCar() {
num++;
}
@Override
void moveCar(int currentX, int currentY, int newX, int newY) {
System.out.println("MidgetCar");
System.out.println("X : " + newX);
System.out.println("Y : " + newY);
}
}
SprintCar (ConcreteFlyweight)
public class FlyweightSprintCar extends RaceCar {
public static int num;
public FlyweightSprintCar() {
num++;
}
@Override
void moveCar(int currentX, int currentY, int newX, int newY) {
System.out.println("SprintCar");
System.out.println("X : " + newX);
System.out.println("Y : " + newY);
}
}
CarFactory (FlyweightFactory)
- 무거운 ConcreteFlyweight 의 경우에는, 인스턴스를 최대 한 개 까지만 생성한 뒤 공유할 수 있도록 합니다.
- 아래의 코드에서는 HashMap 을 이용하여 문자열에 해당하는 인스턴스를 반환하도록 합니다.
public class CarFactory {
private static Map<String, RaceCar> flyweights = new HashMap<>();
public static RaceCar getRaceCar(String key) {
if(flyweights.containsKey(key)) {
return flyweights.get(key);
}
RaceCar raceCar;
switch (key) {
case "Midget":
raceCar = new FlyweightMidgetCar();
raceCar.setName("Midget Car");
raceCar.setSpeed(140);
raceCar.setHorsePower(400);
break;
case "Sprint":
raceCar = new FlyweightSprintCar();
raceCar.setName("Sprint Car");
raceCar.setSpeed(160);
raceCar.setHorsePower(1000);
break;
default:
throw new IllegalArgumentException("Unsupported Car Type.");
}
flyweights.put(key, raceCar);
return raceCar;
}
}
Client (RaceCarClient)
- 자동차보다 상대적으로 가벼운 인스턴스인 운전수의 경우에 대해서
- 위치값 (X, Y) 에 대한 값을 갖고있도록 하여 RAM 을 최적화합니다.
public class RaceCarClient {
private RaceCar raceCar;
public RaceCarClient(String name) {
raceCar = CarFactory.getRaceCar(name);
}
private int currentX = 0;
private int currentY = 0;
public void moveCar(int newX, int newY) {
raceCar.moveCar(currentX, currentY, newX, newY);
currentX = newX;
currentY = newY;
}
}
Usage
@Test
void test() {
RaceCarClient raceCars[] = {
new RaceCarClient("Midget"),
new RaceCarClient("Midget"),
new RaceCarClient("Midget"),
new RaceCarClient("Midget"),
new RaceCarClient("Sprint"),
new RaceCarClient("Sprint")
};
raceCars[0].moveCar(1, 2);
raceCars[1].moveCar(3, 4);
raceCars[4].moveCar(5, 6);
assertEquals(1, FlyweightMidgetCar.num);
assertEquals(1, FlyweightSprintCar.num);
}
참고
'디자인패턴' 카테고리의 다른 글
퍼사드 패턴 (Facade Pattern) (0) | 2021.07.10 |
---|---|
장식자 패턴 (Decorator Pattern) (0) | 2021.07.10 |
복합체 패턴 (Composite Pattern) (0) | 2021.06.19 |
브릿지 패턴 (Bridge Pattern) (0) | 2021.06.18 |
어댑터 패턴 (Adapter pattern) (0) | 2021.06.12 |