-
예약, 예매 시스템에 대한 고찰-2프로그래밍 2024. 10. 16. 00:07
필자는 예매 시스템을 유지보수 및 개발한 적이 있다.
그 경험을 공유하고자 한다.
영화 예매를 기준으로 아래와 같이 설명한다.
영화 예매는 3자 중계 서비스다.
예매자
|
중계자
|
-------------- + -------------
| |
극장사 예매처
여기서 예매자는 고객, 즉, 당신이다.
중계자는 티켓 중계 사이트이다.
극장 사는 CGV, 롯데시네마, 메가박스 등이다.
예매처는 NAVER, KAKAO, LGT, SKT, KT 등이다.
중계자는 극장사로부터 영화의 예매 권리를 사는 행위를 하고
예매처로부터는 고객의 할인이나 쿠폰등의 마케팅 및 결제 처리를 담당한다.
따라서, 중계자는 극장사로부터 영화 정보 및 좌석, 금액 같은 정보를 획득하여 예매자에게 노출하고
예매자가 선택한 영화에 예매처의 할인이나 마케팅 수단 및 결제 수단 등을 결합하여 최종적으로 영화 예매가 완성된다.
이번에는 예매를 하는 코드의 기본 골격을 알아보자.
코드는 아래와 같다.
namespace ConsoleApp1; public class ReserveResult { } public class PaymentResult { } public interface IProviderRollback { void Rollback(); } public interface IMovieProvider: IProviderRollback { ReserveResult Reserve(); } public interface IPaymentProvider: IProviderRollback { PaymentResult Payment(); } public class CgvProvider : IMovieProvider { public ReserveResult Reserve() { Console.WriteLine("Cgv Reserve Complete."); return new ReserveResult(); } public void Rollback() { Console.WriteLine("Cgv Reserve Rollback."); } } public class LotteProvider : IMovieProvider { public ReserveResult Reserve() { Console.WriteLine("Lotte Reserve Complete."); return new ReserveResult(); } public void Rollback() { Console.WriteLine("Lotte Reserve Rollback."); } } public class NaverPaymentProvider : IPaymentProvider { public PaymentResult Payment() { Console.WriteLine("Naver Payment Complete."); return new PaymentResult(); } public void Rollback() { Console.WriteLine("Naver Payment Rollback."); } } public class KakaoPaymentProvider : IPaymentProvider { public PaymentResult Payment() { throw new Exception("Kakao Payment Error."); } public void Rollback() { Console.WriteLine("Kakao Payment Rollback."); } } public class MovieProviderFactory { private static Lazy<MovieProviderFactory> _instance { get; } = new Lazy<MovieProviderFactory>(() => new MovieProviderFactory()); public static MovieProviderFactory Instance => _instance.Value; private Dictionary<string, IMovieProvider> _movieProviders = new Dictionary<string, IMovieProvider>() { { "Cgv", new CgvProvider() }, { "Lotte", new LotteProvider() }, }; private Dictionary<string, IPaymentProvider> _paymentProviders = new Dictionary<string, IPaymentProvider>() { { "Naver", new NaverPaymentProvider() }, { "Kakao", new KakaoPaymentProvider() }, }; private MovieProviderFactory() { } public IMovieProvider GetMovieProvider(string movieName) { return _movieProviders[movieName]; } public IPaymentProvider GetPaymentProvider(string paymentName) { return _paymentProviders[paymentName]; } }
using ConsoleApp1; var provider = MovieProviderFactory.Instance.GetMovieProvider("Cgv"); var payment = MovieProviderFactory.Instance.GetPaymentProvider("Naver"); try { var reserveResult = provider.Reserve(); var paymentResult = payment.Payment(); //TODO : save result data. //example /* * var storeData = new StoreData(); * storeData.ReserveId = reserveResult.Id; * storeData.PaymentId = paymentResult.Id; * ... * ... * ... * dbContext.Results.Add(storeData); * dbContext.SaveChanges(); */ Console.WriteLine("save store data."); } catch (Exception e) { //rollback provider.Rollback(); payment.Rollback(); }
위와 같은 코드가 되겠다.
다수의 극장사와 다수의 예매처를 처리하기 위해 각각 공통 인터페이스를 상속받고 있다.
이 공통 인터페이스로 모든 파라메터를 공통화하고 극장사 및 예매처를 별도로 관리하면서 메인이 되는 플로우 코드를 하나로 관리할 수 있다.
이는 분명한 이점이 있다.
만약 이러한 코드를 모두 if-else로 처리한다면 그 코드 양은 상당할 것이다.
또한 상태 관리를 위해 선택 조건을 Dictionary로 관리하고 있는데 이는 매우 유용한 방법이다.
위와 같은 코드는 예가 영화 예매 시스템일 뿐 이와 유사한 논리가 적용되는 어떤 논리에도 적용할 수 있다.
요점은 같은 행위를 하는 주체들이 다수일 경우에 하나로 묶어서 관리할 수 있고
이러한 경우에 if-else보다는 추상화를 통해서 모듈화하여 별도로 관리할 수 있는 코드를 작성하는 데 있겠다.
도움이 되길 바라며...
'프로그래밍' 카테고리의 다른 글
SignalR Redis Backplane (0) 2024.10.16 EF CORE의 상태 변경 (1) 2024.10.16 Entity Framework는 Unit of Work가 필요한가? (0) 2024.10.14 멀티스레드 환경에서의 데이터 전송에 대한 안정성 향상 방법 (3) 2024.10.10 테이블 캐시를 관리하는 방법 (0) 2024.10.04