11. 4 구현
플라이급 패턴의 예제 프로그램은 Meta, MetaPool, PictureFile, 데모 코드 순으로 구현합시다.
11.4.1 Meta
Meta 형식에서는 카메라의 Body 종류에 대한 열거형 멤버와 렌즈 종류에 해당하는 열거형 멤버, 조명에 대한 열거형 멤버를 갖고 있게 합시다. 그리고 같은 멤버의 값을 가졌는지 비교하는 메서드와 이들 정보를 보여주는 메서드를 제공할 것입니다.
▶ Meta.cs
using System; namespace Flyweight { //사진 촬영 조건에 관한 열거형 정의 public enum BodyType { EH_BA, EH_BB, EH_BC }; public enum LensType { EH_L1, EH_L2, EH_L3 }; public enum LightType { LT_CLEAR, LT_CLOUDY, LT_LAMP }; class Meta //사진 파일들이 공유할 수 있는 촬영 조건을 정의한 클래스 { static readonly string[] bodyname = {"EH_BA","EH_BB","EH_BC"}; static readonly string[] lensname = { "EH_L1", "EH_L2", "EH_L3" }; static readonly string[] lightname = { "맑음", "흐림", "램프" }; //촬영 조건에 대한 속성들 public BodyType Body { get; private set; } public LensType Lens { get; private set; } public LightType Light { get; private set; } readonly int seq; //일련번호 static int scnt; //Meta 개체 수 public Meta(BodyType body,LensType lens,LightType light) { scnt++; seq = scnt; //개체 생성 순으로 일련번호 부여 Body= body; Lens = lens; Light = light; } // 촬영조건이 같은지 확인하는 메서드 public bool IsEqual(BodyType body,LensType lens,LightType light) { return (Body==body)&&(Lens==lens)&&(Light==light); } public void View() { Console.WriteLine("일련번호:{0}", seq); Console.WriteLine("Body:{0}",bodyname[(int)Body]); Console.WriteLine("Lens:{0}", bodyname[(int)Lens]); Console.WriteLine("Light:{0}", bodyname[(int)Light]); } } }
11.4.2 MetaPool
MetaPool은 같은 멤버 값을 갖지 않게 Meta 개체들을 관리하는 개체입니다. MetaPool에서는 원하는 상태를 갖는 Meta 개체를 참조할 수 있는 메서드를 제공해야 합니다. 여기에서는 MakeMeta 이름을 갖는 메서드로 제공할 것입니다.
MakeMeta 메서드에서는 입력 인자로 들어온 Body 종류, 렌즈 종류, 조명을 값으로 하는 Meta 개체가 이미 존재하는지를 확인합니다. 이미 존재한다면 해당 Meta 개체를 반환하고 존재하지 않을 때에는Meta 개체를 생성하여 보관하고 이를 반환하게 작성하면 될 것입니다. 그리고 MetaPool 개체를 단일체(Singleton)로 정의하였습니다.
▶ MetaPool.cs
using System.Collections.Generic; namespace Flyweight { class MetaPool // Meta 개체들을 관리하는 클래스 { List<Meta> metas = new List<Meta>(); //Meta 개체 보관하는 컬렉션 public static MetaPool Singleton //단일체 속성 { get; private set; } static MetaPool()//단일체를 생성하는 정적 생성자 { Singleton = new MetaPool(); } private MetaPool()//단일체 구현을 위해 private으로 접근 지정 { } //촬영 조건에 해당하는 Meta 개체를 반환하는 메서드 public Meta MakeMeta(BodyType body,LensType lens,LightType light) { //같은 촬영 조건의 Meta 개체가 있으면 해당 개체를 반환 foreach (Meta meta in metas) { if (meta.IsEqual(body, lens, light)) { return meta; } } //없을 때 Meta m = new Meta(body,lens,light); //새로운 Meta 개체 생성 metas.Add(m); //컬렉션에 보관 return m; } } }
11.4.3 PicureFile
PictureFile은 MetaPool을 통해 사진이 찍은 환경에 해당하는 Meta 개체의 위치 정보를 갖도록 구현해 봅시다. 생성자 메서드에서는 사진 이름과 사진을 찍은 환경 값에 해당하는 Body 종류, Lens 종류, 조명 값을 인자로 받습니다. 생성자에서 입력 인자를 값으로 하는 Meta 개체를 참조하기 위하여 MetaPool 단일체 개체의 MakeMeta 메서드를 호출합니다. 모든 PictureFile마다 사진을 찍은 환경 정보를 갖고 있게 하였다면 같은 정보를 갖는 PictureFile 개체가 많아지면 메모리 효율이 떨어집니다. 하지만 예제 프로그램처럼 플라이급 패턴을 적용하면 같은 정보를 갖는 PictureFile 개체가 아무리 많아져도 환경 정보가 같은 개체들은 하나의 Meta 개체를 참조하므로 메모리 효율을 높일 수 있습니다.
▶ PictureFile.cs
using System; namespace Flyweight { class PictureFile { string name; Meta meta; //사진을 찍을 때의 환경 정보 public PictureFile(string name,BodyType body,LensType lens,LightType light) { MetaPool meta_pool = MetaPool.Singleton; //환경 정보에 맞는 Meta 개체를 MetaPool에게 요청하여 참조 함 meta = meta_pool.MakeMeta(body,lens,light); } public void View() { Console.WriteLine("사진 이름:{0}",name); meta.View(); } } }
11.4.4 데모 코드
▶ Program.cs
namespace Flyweight { class Program { static void Main(string[] args) { BodyType body_type = BodyType.EH_BA; LensType lens_type = LensType.EH_L1; LightType light_type = LightType.LT_CLEAR; PictureFile pf = new PictureFile("사진", body_type, lens_type, light_type); PictureFile pf2 = new PictureFile("사진", body_type, lens_type, light_type); pf.View(); pf2.View(); } } }
▶ 실행 결과
사진 이름: 일련번호:1 Body:EH_BA Lens:EH_BA Light:EH_BA 사진 이름: 일련번호:1 Body:EH_BA Lens:EH_BA Light:EH_BA