디자인 패턴 톺아보기 - Flyweight Pattern

Updated:

1. 플라이웨이트 패턴(Flyweight Pattern) 이란?

GOF 에서 말하는 플라이웨이트 패턴의 목적은 아래와 같습니다.

Use sharing to support large numbers of fine-grained objects efficiently.

공유를 통해 많은 수의 소립(fine-grained) 객체들을 효과적으로 지원합니다.

1.1. 구조

Sample / Sequence Diagram

image

  • Flyweight
    • Flyweight 가 받아들일 수 있고, 부가적인 상태에서 동작해야 하는 인터페이스를 선언합니다.
  • ConcreteFlyweight
    • Flyweight 인터페이스를 구현하고 내부적으로 갖고 있어야 하는 본질적 사앹에 대한 저장소를 정의합니다. ConcreteFlyweight 객체는 공유할 수 있는 것이어야 합니다. 그러므로 관리하는 어떤 상태로도 본질적인 것이어야 합니다.
  • UnsharedConcreteFlyweight
    • 모든 플라이급 서브클래스들이 공유될 필요는 없습니다. Flyweight 인터페이스는 공유를 가능하게 하지만, 그것을 강요해서는 안 됩니다. UnsharedConcreteFlyweight 객체가 ConcreteFlyweight 객체를 자신의 자식으로 갖는 것은 흔한 일입니다.
  • FlyweightFactory
    • 플라이급 객체를 생성하고 관리하며, 플라이급 객체가 제대로 공유되도록 보장합니다. 사용자가 플라이급 객체를 요청하면 FlyweightFactory 객체는 이미 존재하는 인스턴스를 제공하거나 만약 존재하지 않는다면 새로 생성합니다.
  • Client
    • 플라이급 객체에 대한 참조자를 관리하며 플라이급 객체의 부가적 상태를 저장합니다.

1.2. 사용 방법

  • 플라이급 객체가 기능을 수행하는 데 필요한 상태가 본질적인 것인지 부가적인것인지를 구분해야 합니다. 본질적 상태는 ConcreteFlyweight에 저장해야 하고, 부가적인 상태는 사용자가 저장하거나, 연산되어야 하는 다른 상태로 관리해야 합니다.
  • 사용자는 연산을 호출할 때 자신에게만 필요한 부가적 상태를 플라이급 객체에 매개변수로 전달합니다.
  • 사용자는 ConcreteFlyweight의 인스턴스를 직접 만들 수 없습니다. 사용자는 ConcreteFlyweight 객체를 FlyweightFactory 객체에서 얻어야 합니다. 이렇게 해야 플라이급 객체가 공유될 수 있습니다.

1.3. 장/단점

  • Advantages (+)
    • Enables abstractions at the finest levels
  • Disadvantages (–)
    • Introduces run-time costs
    • Provides no reliability on object identity.

1.4. 고려사항

  • Consider the left design (problem):
    • Large number of physically created objects.
  • Consider the right design (solution):
    • Small number of physically created objects.

2. 플라이웨이트 패턴(Flyweight Pattern) 사용예시

플라이웨이트 패턴은 언제 사용하는가에 따라 그 효과가 달라집니다. 다음의 경우에 사용할 수 있습니다.

  • 응용프로그램이 대량의 객체를 사용해야 할 때
  • 객체의 수가 너무 많아져 저장 비용이 너무 높아질 때
  • 대부분의 객체 상태를 부가적인 것으로 만들 수 있을 때
  • 부가적인 속성들을 제거한 후 객체들을 조사해보니 객체의 많은 묶음이 비교적 적은 수의 공유된 객체로 대체될 수 있을 때
  • 응용 프로그램이 객체의 정체성에 의존하지 않을 때

2.1. GOF 패턴

2.1.1. Flyweight

interface Flyweight {
	public String operation(int extrinsicState);
}

2.1.2. ConcreteFlyweight

class ConcreteFlweight implements Flyweight {
	private String intrinstcState;
	
	public ConcreteFlweight(String intrinstcState) {
		this.intrinstcState = intrinstcState ;
	}
	
	public String operation(int extrinsicState) {
        return "  performing an operation on the flyweight\n "
        		+ " with intrinsic state = " + this.intrinstcState
        		+ " and passed in extrinsic state = " + extrinsicState + ".";
	}
}

2.1.3. FlyweightFactory

class FlyweightFactory { 
	 // Implemented as Singleton.
	 // See also Singleton / Implementation / Variant 1.
	 private static final FlyweightFactory INSTANCE = new FlyweightFactory();
	 
	 private FlyweightFactory() { }
	 
	 public static FlyweightFactory getInstance() { 
		return INSTANCE;
	 }
	 
	 // Shared flyweight pool.
	 private Map<String, Flyweight> flyweights = new HashMap<String, Flyweight>();
	 
	 // Creating and maintaining shared flyweights.
	 public Flyweight getFlyweight(String key) { 
		 if (flyweights.containsKey(key)) { 
			 System.out.println("Sharing a flyweight with key = " + key);
			 return flyweights.get(key);            
		 }  else { 
			 System.out.println("Creating a flyweight with key = " + key);
			 Flyweight flyweight = new ConcreteFlweight(key); // assuming key = intrinsic state
			 flyweights.put(key, flyweight);
			 return flyweight;
		 } 
	 }
	 
	 public int getSize() { 
		 return flyweights.size();
	 } 
} 

2.1.4. Client

public class Main{
	public static void main(String[] args) {
		Flyweight flyweight;
		
		FlyweightFactory flyweightFactory = FlyweightFactory.getInstance();
		
		flyweight = flyweightFactory.getFlyweight("A");
		System.out.println(flyweight.operation(100));
		
		flyweight = flyweightFactory.getFlyweight("A");
		System.out.println(flyweight.operation(200));
		
		flyweight = flyweightFactory.getFlyweight("B");
		 
		System.out.println("\n*** Number of flyweights created: " + flyweightFactory.getSize() + " ***");
	}
}

결과는 아래와 같습니다.

Creating a flyweight with key = A
  performing an operation on the flyweight
  with intrinsic state = A and passed in extrinsic state = 100.
Sharing a flyweight with key = A
  performing an operation on the flyweight
  with intrinsic state = A and passed in extrinsic state = 200.
Creating a flyweight with key = B

*** Number of flyweights created: 2 ***

참고 자료

Leave a comment