Delphi 모드 프로그래밍의 전략 모드(계속)
리우 이
1.3 호텔경영시스템에 전략모델 적용
호텔 관리 시스템에서 객실 가격은 일반적으로 고정되어 있지 않습니다. 숙박시설의 비수기와 성수기, 기존 고객과 신규 고객, 개인 고객과 단체에 따라 판매 전략이 달라야 한다. 분명히 판매 전략에 따라 제안이 결정됩니다. 그러나 판매전략에 기초한 견적시스템은 특정 고객에게 구속될 수 없다. 왜냐하면 판매전략에 기초한 견적시스템을 독립화해야만 재사용성과 유지보수성이 보장되기 때문이다. 예를 들어, 견적 시스템은 우대 객실 요금 문의 및 객실 정산과 같은 여러 고객의 요구를 충족시키는 한편, 새로운 판매 전략을 지속적으로 조정하는 요구를 충족시켜 실제로 재사용성과 유지 관리성을 달성할 수 있습니다. . 위의 설계 요구 사항에 대해서는 전략 모드를 선택하는 것이 가장 좋습니다. 전략 패턴을 사용하면 이를 사용하는 클라이언트와 관계없이 알고리즘 변경이 가능합니다. 샘플 프로그램은 전략 모델 기반의 주택 우대 가격 조회 모듈로, 판매 전략에 따른 견적 시스템과 주택 우대 가격 조회 인터페이스를 포함하고 있습니다. 물론 우대 가격 조회 인터페이스는 견적 시스템의 클라이언트 중 하나일 뿐이며 다른 클라이언트도 견적 시스템을 사용할 수 있습니다. 우대가격조회모듈의 설계는 그림 1-6과 같다. 여기에는 다음이 포함됩니다. · 특정 판매 전략 클래스에 대한 추상 기본 클래스인 판매 전략 클래스 TSaleStrategy. · 3가지 구체적인 영업 전략 카테고리: TVipStrategy(VIP 카드 영업 전략), TTeamStrategy(팀 영업 전략), TSeasonStrategy(계절별 영업 전략). · 이 전략 패턴의 컨텍스트이고 TStrategy에 대한 참조를 보유하는 인용 클래스 TPRiceContext. · 클라이언트 클래스 TClient는 주택 가격 조회를 위한 인터페이스인 폼 클래스입니다. 그림 1-6 전략 패턴에 따른 우대 객실 요금 조회 모듈의 샘플 프로그램 1-1은 HotelSaleStrategy 유닛의 소스 코드이며, 이 유닛은 판매 전략에 따른 견적 시스템의 비즈니스 로직을 포함하고 있으며, 전략 패턴. TSaleStrategy는 영업 전략의 추상 기본 클래스로서 공통 인터페이스를 제공하는 것을 목표로 합니다. 가상 추상 함수 SalePrice가 그러한 인터페이스입니다. 세 가지 특정 판매 전략은 시즌, VIP 카드 및 팀 규모를 기반으로 공식화되므로 기본 클래스 인터페이스 SalePrice의 매개 변수 디자인은 세 가지 파생 클래스의 다양한 요구 사항을 충족해야 합니다. TSaleStrategy의 SalePrice 함수는 다음과 같이 선언됩니다. function SalePrice(price:Currency;value:integer):Currency; abstract; 첫 번째 매개변수는 들어오는 고정 가격을 나타내고 두 번째 매개변수는 들어오는 우대 조건을 나타냅니다. 다른 파생 클래스의 경우. 시즌 판매 전략 TSeasonStrategy에서 이 매개변수는 VIP 카드 판매 전략 TVIPStrategy에서 체크인 월로 표시되고, 이 매개변수는 팀 판매 전략 TTeamStrategy에서 VIP 카드 유형으로 표시됩니다. 팀의 사람 수. 우리는 이러한 매개변수가 모두 정수 유형을 사용할 수 있다는 것을 알았습니다. 따라서 기본 클래스에서는 파생 클래스의 다양한 매개변수 요구사항을 해결하기 위해 값 매개변수가 교묘하게 사용됩니다. 이러한 방식으로 TPriceContext는 데이터를 매개변수에 직접 입력하고 매개변수 중복을 방지하면서 다양한 판매 전략 작업에 전달할 수 있습니다. {TPriceContext }함수 TPriceContext.GetPrice(price:Currency;value:integer):Currency;begin result:=Strategy.SalePrice(price,value);end;TPriceContext는 이 전략 모드에서 상황에 맞는 역할을 하며 판매 참조를 담당합니다. 전략 객체의 다양한 인스턴스는 SalePrice 인터페이스를 호출하여 특정 할인 알고리즘을 동적으로 구성하고 실제 판매 가격을 반환합니다. TPriceContext의 중개로 인해 클라이언트는 특정 판매 전략이 어떻게 구현되는지 알 필요가 없습니다. 마찬가지로 판매 전략이 업데이트되고 조정되면 클라이언트 프로그램에 영향을 미치지 않습니다. 샘플 프로그램 1-1 HotelSaleStrategy 유닛의 소스 코드 HotelSaleStrategy; 인터페이스는 SysUtils, Windows, 메시지, 클래스, 그래픽, 컨트롤, 양식, 대화 상자를 사용합니다. TSaleStrategy = 클래스(TObject) 공용 함수 SalePrice(price:Currency;value:integer): 통화 ; 가상; 종료; TSeasonStrategy = 클래스(TSaleStrategy) SalePrice(price:Currency;value:integer):Currency; end; TVIPStrategy = 클래스(TSaleStrategy) 공용 함수 SalePrice(price:Currency;value:integer):Currency; SalePrice(가격:통화;값:정수):통화; TPriceContext = class; (TObject) private FStrategy: TSaleStrategy; 절차 SetStrategy(값: TSaleStrategy); 공용 함수 GetPrice(price:Currency;value:integer):Currency; 속성 전략: TSaleStrategy read SetStrategy; TSeasonStrategy.SalePrice(price:Currency;value:integer):Currency;begin //계절 판매 전략 {2월, 3월, 11월 15% 할인, 4월, 6월 10% 할인. 8. 9월에는 9.5% 할인됩니다. } 사례 값 2,3,11:result:=price*0.85; 4,6:result:=price*0.9; else result:=price;end; TVIPStrategy }function TVIPStrategy.SalePrice(price:Currency;value:integer):Currency;begin //VIP 카드 판매 전략{ 0: VIP 실버 카드 10% 할인 1: VIP 골드 카드 20% 할인 2: VIP 다이아몬드 카드 30% 할인} 케이스 값 0:result:=price*0.9; 1:result:=price*0.8; :결과: =가격*0.7; end;end;{TTeamStrategy }함수 TTeamStrategy.SalePrice(price:Currency;value:integer):Currency;begin //팀 판매 전략 {3~5명 팀의 경우 10% 할인, 6~10명 팀의 경우 30% 할인; 11-20명으로 구성된 팀, 1명 이상의 그룹은 20% 할인됩니다. } 결과:=가격; if (값<6) 및 (값>2) 결과:=가격*0.9; if (값<11) 및 (값>5) 결과:=가격*0.8; 21) 및 (값>10)이면 결과:=price*0.7; if (값>20)이면 결과:=price*0.6;end;{TPriceContext }함수 TPriceContext.GetPrice(price:Currency;value:integer):Currency;begin result:=Strategy.SalePrice(price,value);end;procedure TPriceContext.SetStrategy(Value: TSaleStrategy);begin FStrategy:=Value;end;end. 샘플 프로그램 1-2는 우대 객실 요금 조회 모듈의 클라이언트 프로그램을 보여줍니다. 프로그램은 문의자가 우대요금제를 선택할 수 있도록 사용자 선택 인터페이스를 제공합니다. 우대조건과 공시요금을 선택하신 후, "우대요금 확인" 버튼을 클릭하시면 할인된 요금을 받으실 수 있습니다. 실제 작동 효과는 그림 1-7에 나와 있습니다. 샘플 프로그램 1-2 ClientForm 유닛 소스 코드 유닛 ClientForm; 인터페이스는 Windows, 메시지, SysUtils, 변형, 클래스, 그래픽, 컨트롤, 양식, 대화 상자, StdCtrls, ExtCtrls, HotelSaleStrategy, ComCtrls,DateUtils를 사용합니다. TRadioGroup; TButton; TButton; cmbVIP: TComboBox; cmbPrice: TLabel; TLabel; 프로시저 FormCreate(발신자: TObject); 프로시저 btnCheckClick(Sender: TObject); 프로시저 RadioGroup1Click(Sender: TObject); FVIPSStrategy:TSaleStrategy; TPriceContext; { 공개 선언 } end;var 클라이언트: TClient;implementation{$R *.dfm}절차 TClient.FormCreate(Sender: TObject);begin FSeasonStrategy:=TSeasonStrategy.Create; FVIPStrategy:=TVIPStrategy:=TTeamStrategy.Create; ; FPriceSys:=TPriceContext.Create;end;procedure TClient.btnCheckClick(Sender: TObject);var i:integer; Price:Currency;begin case RadioGroup1.ItemIndex of 0:begin FPriceSys.Strategy:=FSeasonStrategy i:=MonthOf(dtpDate .날짜시간) 1:시작; FPriceSys.Strategy:=FVIPStrategy ; i:=cmbVIP.ItemIndex; 2:begin FPriceSys.Strategy:=FTeamStrategy ; i:=StrToInt(edtCount.Text) end; 300; //A급 스탠다드룸은 300위안입니다. 1:price:=500; //B등급 스탠다드룸은 500위안 2:price:=800; //VIP룸은 800위안 3:price:=1000; //비즈니스 스위트룸은 1,000위안 4:price:=2000 //디럭스 스위트룸은 2,000위안 yuanend; edtPrice .Text:=CurrToStr(FPriceSys.GetPrice(price,i));end;절차 TClient.FormDestroy(발신자: TObject); 시작 FPriceSys.Free; FVIPStrategy.Free;end; 프로시저 TClient.btnExitClick(Sender: TObject); edtCount.Enabled:=false; cmbVIP.Enabled:=false; 0:dtpDate.Enabled:=true; 2:edtCount.Enabled:=true; 그림 1-7 우대 가격 조회 모듈의 실제 실행 인터페이스
1.4 실습 요약
이전 예제의 시연 및 분석을 통해 다음과 같이 전략 패턴에 대해 자세히 설명합니다. · 전략 패턴은 일련의 알고리즘을 관리하는 방법을 제공합니다. 전략 클래스의 계층 구조는 TContext에 대한 일련의 재사용 가능한 알고리즘 또는 동작을 정의합니다. TStrategy 기본 클래스는 이러한 알고리즘의 공통 기능을 추출하고 파생 클래스는 상속을 통해 알고리즘의 차이점과 유형을 강화하고 코드 중복을 방지합니다. · 알고리즘이 사용되는 컨텍스트에서 알고리즘을 분리하지 않고, 알고리즘이 포함된 TContext 클래스의 파생 클래스를 직접 생성하고 이에 다른 동작을 부여하면 동작을 TContext에 하드 코딩하게 되며, TContext에서 알고리즘 구현을 분리합니다. 구현이 혼합되어 TContext를 이해, 유지 관리 및 확장하기가 어렵습니다. 최종 결과는 관련된 클래스의 묶음이며, 이들 사이의 유일한 차이점은 그들이 사용하는 알고리즘입니다. 분명히 클래스의 상속 관계는 강력한 연관이며 상속 관계는 알고리즘을 동적으로 변경할 수 없지만 객체의 구성 관계는 약한 연관입니다. 전략 클래스 객체를 결합하면 알고리즘이 환경(TContext)과 독립적으로 발전할 수 있습니다. 알고리즘이 사용되는 곳입니다. · 다수의 조건 분기문을 사용하는 프로그램 코드를 리팩터링하려면 전략 패턴을 사용하십시오. 클래스에 다양한 동작이 쌓이면 적절한 동작을 선택하기 위해 조건문을 사용하지 않는 것이 어렵습니다. 별도의 정책 클래스에 동작을 캡슐화하면 이러한 조건문이 제거됩니다. · 알고리즘이 너무 많으면 정책 개체 수가 많아질 수 있습니다. 시스템 오버헤드를 줄이기 위해 일반적으로 알고리즘 환경에 따른 상태를 클라이언트에 저장할 수 있으며, TStrategy는 다양한 클라이언트에서 공유할 수 있는 상태 비저장 개체로 구현됩니다. 모든 외부 상태는 TContext에 의해 유지됩니다. TContext는 TStrategy 객체에 대한 모든 요청에서 이 상태를 전달합니다. 예를 들어 샘플 프로그램에서는 TSeasonStrategy의 외부 상태 체크인 월, TVIPStrategy의 외부 상태 VIP 카드 유형 및 TTeamStrategy의 외부 상태 팀 규모를 클라이언트에 저장하고 이러한 상태를 TPriceContext를 통해 영업 전략 클래스에 전달합니다. 이것의 장점은 판매 전략 클래스가 Stateless가 되어 객실 정산 모듈과 같은 다른 모듈에서 공유할 수 있다는 것입니다. · 각 특정 전략에 의해 구현된 알고리즘이 단순하든 복잡하든 상관없이 모두 TStrategy에서 정의한 인터페이스를 공유합니다. 따라서 일부 특정 정책은 이 인터페이스를 통해 전달된 모든 정보를 사용하지 않을 가능성이 높습니다. 샘플 프로그램에서 TSaleStrategy의 인터페이스를 다음과 같이 디자인하면 다음과 같습니다.
SalePrice(가격:통화;월:정수;VIP:정수;
개수:정수):통화;
이러한 매개변수 중 일부는 특정 판매 전략 클래스에서 절대 사용되지 않습니다. 이는 때때로 TContext가 결코 사용되지 않을 매개변수를 생성하고 초기화한다는 것을 의미합니다. 그러한 문제가 있고 샘플 프로그램의 기술을 사용할 수 없는 경우 TStrategy와 TContext 간에 긴밀하게 결합된 방법만 채택할 수 있습니다.
더 많은 관련 기사와 샘플 프로그램 소스 코드는 저자 웹사이트(http://www.liu-yi.net)에서 다운로드할 수 있습니다.