Стратегический режим программирования в режиме Delphi (продолжение)
Лю Йи
1.3 Применение стратегической модели в системе управления гостиницей
В системах управления гостиницей обычно цена за номер не статична. Должны быть разные стратегии продаж для межсезонья и пикового сезона размещения, старых клиентов и новых клиентов, отдельных гостей и групп. Очевидно, что стратегия продаж определяет предложение. Однако систему котировок, основанную на стратегии продаж, нельзя привязать к конкретному клиенту, поскольку только сделав систему котировок, основанную на стратегии продаж, независимой, можно гарантировать ее многоразовость и ремонтопригодность. Например: с одной стороны, система котировок отвечает потребностям множества клиентов, например, запросу льготной стоимости номера и расчету стоимости номера, с другой стороны, она отвечает потребностям постоянной корректировки новых стратегий продаж. Это действительно может обеспечить возможность повторного использования и удобства обслуживания; . Для вышеуказанных требований к проектированию лучше всего выбрать режим стратегии. Шаблон «Стратегия» позволяет изменять алгоритм независимо от того, использует ли его клиент. Пример программы представляет собой модуль запроса льготных цен на жилье, основанный на стратегической модели, который включает в себя систему котировок, основанную на стратегии продаж, и интерфейс запроса льготных цен на жилье. Конечно, интерфейс запроса льготных цен является только одним из клиентов системы котировок, и система котировок также может использоваться другими клиентами. Конструкция модуля запроса льготных цен показана на рисунке 1-6. Он включает в себя: · Класс стратегии продаж TSaleStrategy, который является абстрактным базовым классом для конкретных классов стратегии продаж. · 3 конкретные категории стратегий продаж: TVipStrategy (стратегия продаж VIP-карт), TTeamStrategy (стратегия командных продаж), TSeasonStrategy (стратегия сезонных продаж). · Класс котировок TPRiceContext, который является контекстом в этом шаблоне стратегии и содержит ссылку на TStrategy. · Клиентский класс TClient — это класс формы, который является интерфейсом для запроса цен на жилье. Рис. 1-6 Пример программы 1-1 модуля запроса льготной стоимости номера на основе шаблона стратегии представляет собой исходный код модуля HotelSaleStrategy. Этот модуль содержит бизнес-логику системы котировок на основе стратегии продаж и реализуется с использованием модуля. образец стратегии. Будучи абстрактным базовым классом стратегии продаж, TSaleStrategy стремится предоставить общий интерфейс. Таким интерфейсом является виртуальная абстрактная функция SalePrice. Поскольку три конкретные стратегии продаж формулируются на основе сезона, VIP-карты и размера команды, конструкция параметров интерфейса базового класса SalePrice должна отвечать различным потребностям трех производных классов. Функция SalePrice TSaleStrategy объявляется следующим образом: function SalePrice(price:Currency;value:integer):Currency Abstract; Ее первый параметр представляет входящую фиксированную цену, а второй параметр представляет входящие льготные условия. для разных производных классов. В стратегии сезонных продаж TSeasonStrategy этот параметр выражается как месяц заезда; в стратегии продаж VIP-карт TVIPStrategy этот параметр выражается как тип VIP-карты, в стратегии командных продаж TTeamStrategy этот параметр выражается как; количество человек в команде. Мы обнаружили, что все эти параметры могут использовать целочисленные типы, поэтому в базовом классе параметр значения умело используется для решения различных требований к параметрам производного класса. Таким образом, TPriceContext может напрямую помещать данные в параметры и передавать их различным операциям стратегии продаж, избегая избыточности параметров. {TPriceContext }function 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): Currency виртуальный; абстрактное; конец; TSeasonStrategy = общественная функция класса (TSaleStrategy); SalePrice(цена: Валюта; значение: целое число): Валюта; переопределить; TVIPStrategy = общедоступная функция класса (TSaleStrategy) SalePrice (цена: Валюта; значение: целое число): Переопределить; SalePrice (цена: Валюта; значение: целое число): Валюта; конец TPriceContext = класс; (TObject) частный FStrategy: TSaleStrategy; процедура SetStrategy (Значение: TSaleStrategy); общественная функция GetPrice (цена: Валюта; значение: целое число): Валюта; Стратегия свойства: TSaleStrategy чтение FStrategy запись SetStrategy; реализация {TSeasonStrategy } function; TSeasonStrategy.SalePrice(price:Currency;value:integer):Currency;begin //Стратегия сезонных продаж {скидка 15 % в феврале, марте и ноябре, скидка 10 % в апреле и июне. 8. Скидка 9,5% в сентябре. } значение случая 2,3,11:result:=price*0.85; 4,6:result:=price*0.9; 8,9:result:=price*0.95; else result:=price end;end;{ TVIPStrategy }function TVIPStrategy.SalePrice(price:Currency;value:integer):Currency;begin //Стратегия продаж VIP-карт{ 0: скидка 10 % на VIP-карту Silver 1: скидка 20 % на VIP-карту Gold 2: скидка 30 % на VIP-карту Diamond} значение случая 0:result:=price*0,9; 1:result:=price*0,8; :result: =price*0.7; end;end;{TTeamStrategy }function TTeamStrategy.SalePrice(price:Currency;value:integer):Currency;begin //Стратегия командных продаж {скидка 10% для команды из 3–5 человек; скидка 20% для команды из 6–10 человек; скидка 30% для команды из 6–10 человек; команда 11-20 человек 20 скидка 40% для групп более 1 человека; } result:=price; if (value<6) and (value>2) then result:=price*0.9; if (value<11) and (value>5) then result:=price*0.8; 21) и (значение>10), то result:=price*0,7; if (value>20), then result:=price*0,6;end;{TPriceContext }function TPriceContext.GetPrice(цена: Валюта;значение:целое число):Валюта;начало результата:=Strategy.SalePrice(цена,значение);конец;процедура TPriceContext.SetStrategy(Значение: TSaleStrategy);begin FStrategy:=Value;конец;конец. Клиентская программа модуля запроса льготной стоимости номера показана в примере программы 1-2. Программа предоставляет интерфейс выбора пользователя, чтобы запрашивавший мог выбрать льготный план. Выбрав льготные условия и общедоступные тарифы, нажмите кнопку «Проверить льготные тарифы», чтобы получить тарифы со скидкой. Фактический эффект работы показан на рисунке 1-7. Пример программы 1‑2. Модуль исходного кода модуля ClientForm; интерфейс использует Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, HotelSaleStrategy, ComCtrls,DateUtils type TClient = class(TForm) RadioGroup1 : ТРАдиоГруппа; TButton; dtpDate: TDateTimePicker; Label1: TLabel; cmbPrice: TComboBox; EDIT; Label3: TLabel; Label4: TLabel; процедура FormCreate(Отправитель: TObject); процедура btnCheckClick (Отправитель: TObject); процедура FormDestroy (Отправитель: TObject); процедура RadioGroup1Click (Отправитель: TObject); FVIPStrategy: TSaleStrategy; TPriceContext; { Публичные объявления } end;var Клиент: TClient;реализация{$R *.dfm}procedure TClient.FormCreate(Sender: TObject);begin FSeasonStrategy:=TSeasonStrategy.Create; FVIPStrategy:=TVIPStrategy.Create; ; FPriceSys:=TPriceContext.Create;end;procedure TClient.btnCheckClick(Sender: TObject);var i:integer; цена:Currency;begin Case RadioGroup1.ItemIndex of 0:begin FPriceSys.Strategy:=FSeasonStrategy ;=MonthOf(dtpDate); .ДатаВремя); конец 1: начало; FPriceSys.Strategy:=FVIPStrategy ; i:=cmbVIP.ItemIndex; end; 2:begin FPriceSys.Strategy:=FTeamStrategy ; i:=StrToInt(edtCount.Text); end; case cmbPrice.ItemIndex of 0:price:= 300; // Стандартный номер класса А — 300 юаней 1:цена:=500; // Стандартный номер класса B — 500 юаней 2:price:=800; //VIP-номер — 800 юаней 3:price:=1000; //Бизнес-люкс — 1000 юаней 4:price:=2000 // Люкс — 2000; yuanend; edtPrice .Text:=CurrToStr(FPriceSys.GetPrice(price,i));end;процедура TClient.FormDestroy(Sender: TObject); начать FPriceSys.Free; FSeasonStrategy.Free; FTeamStrategy.Free; конец; процедура TClient.btnExitClick (Отправитель: TObject); edtCount.Enabled:=false; cmbVIP.Enabled:=false; случай RadioGroup1.ItemIndex: 0:dtpDate.Enabled:=true; 1:cmbVIP.Enabled:=true; 2:edtCount.Enabled:=true end;end; конец Рисунок 1-7 Фактически работающий интерфейс модуля запроса льготных цен.
1.4 Краткое описание практики
Посредством демонстрации и анализа предыдущих примеров мы далее обсудим шаблон стратегии следующим образом: · Шаблон стратегии обеспечивает способ управления набором алгоритмов. Иерархия классов стратегий определяет ряд повторно используемых алгоритмов или поведений для TContext. Базовый класс TStrategy извлекает общие функции в этих алгоритмах, а производные классы обогащают различия и типы алгоритмов посредством наследования и позволяют избежать дублирования кода. · Если вы не отделяете алгоритм от контекста, в котором он используется, а напрямую генерируете производный класс класса TContext, который содержит алгоритм, и задаете ему различное поведение, это жестко запрограммирует поведение в TContext и отделить реализацию алгоритма от TContext. Реализации перепутаны, что затрудняет понимание, поддержку и расширение TContext. Конечным результатом является набор связанных классов, единственная разница между ними — алгоритм, который они используют. Очевидно, что отношения наследования классов являются сильной ассоциацией, и отношения наследования не могут динамически изменять алгоритм, в то время как отношения композиции объектов являются слабой ассоциацией. Комбинируя объекты классов стратегии, алгоритм может развиваться независимо от среды (TContext). в котором используется алгоритм. · Используйте шаблон стратегии для рефакторинга программных кодов, использующих большое количество операторов условного перехода. Когда в классе объединены разные варианты поведения, трудно избежать использования условных операторов для выбора подходящего поведения. Инкапсуляция поведения в отдельных классах политики исключает эти условные операторы. · Слишком большое количество алгоритмов может привести к появлению большого количества объектов политики. Чтобы снизить накладные расходы системы, состояние, которое зависит от среды алгоритма, обычно может быть сохранено на клиенте, а TStrategy реализован как объект без сохранения состояния, который может совместно использоваться различными клиентами. Любое внешнее состояние поддерживается TContext. TContext передает это состояние при каждом запросе к объекту TStrategy. Например, в примере программы я сохраняю месяц проверки внешнего статуса TSeasonStrategy, тип VIP-карты внешнего статуса TVIPStrategy и размер команды внешнего статуса TTeamStrategy на клиенте и передаю эти статусы классу стратегии продаж через TPriceContext. Преимущество этого заключается в том, что класс стратегии продаж становится апатридным, и его можно использовать совместно с другими модулями, такими как модуль расчета номеров. · Независимо от того, является ли алгоритм, реализуемый каждой конкретной стратегией, простым или сложным, все они используют общий интерфейс, определенный TStrategy. Поэтому вполне вероятно, что некоторые конкретные политики не будут использовать всю информацию, передаваемую им через этот интерфейс. Если я спроектирую интерфейс TSaleStrategy в примере программы следующим образом:
SalePrice(цена: Валюта; Месяц: целое число; VIP: целое число;
Количество: целое число): Валюта;
Некоторые из этих параметров никогда не будут использоваться определенными классами стратегий продаж. Это означает, что иногда TContext создает и инициализирует параметры, которые никогда не будут использоваться. Если возникла такая проблема и вы не можете использовать методы из примера программы, вы можете использовать только тесно связанный метод между TStrategy и TContext.
Дополнительные статьи по теме и примеры исходных кодов программ можно загрузить с сайта автора: http://www.liu-yi.net.