a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 編程 > Delphi > 正文

Delphi模式編程之策略模式(下)

2019-11-18 18:23:03
字體:
來源:轉載
供稿:網友

Delphi模式編程之策略模式(續)

劉 藝

1.3                         策略模式在酒店管理系統中的應用

在酒店管理系統中,通??头康膬r格不是一成不變的。對于住宿的淡季和旺季、老客戶和新客戶、散客和團隊,都應該有不同的銷售策略。顯然,銷售策略決定了報價。但是基于銷售策略的報價體系又不能綁定于某一具體的客戶端,因為只有把基于銷售策略的報價體系獨立出來,才能保證其重用性和可維護性。比如:一種報價體系一方面滿足了優惠房價查詢、客房結算等多個客戶端的使用,另一方面又滿足了不斷調整的新銷售策略的需求,這才算真正做到了重用性和可維護性。
對于以上的設計要求,選用策略模式是最好不過了。策略模式能夠讓算法變化獨立于使用它的客戶端。范例程序是一個基于策略模式的優惠房價查詢模塊,它包括一個基于銷售策略的報價體系和一個優惠房價查詢界面。當然,優惠房價查詢界面只是該報價體系的客戶端之一,報價體系亦可被其他客戶端使用。
優惠房價查詢模塊的設計如圖 1‑6所示。它包括了:
·           銷售策略類TSaleStrategy,它是具體銷售策略類的抽象基類。
·           3個具體銷售策略類:TVipStrategy (VIP卡銷售策略)、TTeamStrategy (團隊銷售策略)、TSeasonStrategy(季節銷售策略)。
·           報價類TPRiceContext,它是該策略模式中的上下文,持有一個到TStrategy的引用。
·           客戶端類TClient,它是一個窗體類,即房價查詢的界面。
 
1‑6 基于策略模式的優惠房價查詢模塊
示例程序 1‑1是HotelSaleStrategy單元的源代碼,該單元包含了基于銷售策略的報價體系的業務邏輯,用策略模式實現。TSaleStrategy作為銷售策略的抽象基類,其目的是提供一個通用的接口。虛抽象函數SalePrice就是這樣一個接口。由于3個具體銷售策略分別是根據季節、VIP卡、團隊人數來制定銷售策略的,所以基類接口SalePrice的參數設計必須滿足3個派生類的不同需求。TSaleStrategy的SalePrice函數聲明如下:
 
function SalePrice(price:Currency;value:integer):Currency;
virtual; abstract;
 
 
它的第一個參數表示傳入的固定房價,第二個參數表示傳入的優惠條件,該條件因不同的派生類而異。在季節銷售策略TSeasonStrategy中,該參數表示為入住月份;在VIP卡銷售策略TVIPStrategy中,該參數表示為VIP卡的種類;在團隊銷售策略TTeamStrategy中,該參數表示為團隊人數。我們發現,這些參數都可以用整數類型,所以在基類中,巧妙地用一個value參數解決了派生類的不同參數需求。這樣一來,可以直接讓TPriceContext將數據放在參數中傳遞給不同的銷售策略類操作,避免了參數冗余。
 
{TPriceContext }
function TPriceContext.GetPrice(price:Currency;value:integer):Currency;
begin
  result:=Strategy.SalePrice(price,value);
end;
 
TPriceContext在該策略模式中起著上下文作用,它負責引用銷售策略對象的不同實例,調用SalePrice接口,動態配置具體的折扣算法,并返回實際銷售價格。由于有了TPriceContext的中介,客戶端無需知道具體銷售策略是如何實現的;同樣,當銷售策略進行更新調整時,對客戶端程序亦無影響。
示例程序 1‑1 HotelSaleStrategy單元的源代碼
unit HotelSaleStrategy;
 
interface
 
uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls,
  Forms, Dialogs;
 
type
  TSaleStrategy = class (TObject)
  public
    function SalePrice(price:Currency;value:integer):Currency;
virtual; abstract;
  end;
  TSeasonStrategy = class (TSaleStrategy)
  public
    function SalePrice(price:Currency;value:integer):Currency; override;
  end;
  TVIPStrategy = class (TSaleStrategy)
  public
    function SalePrice(price:Currency;value:integer):Currency; override;
  end;
  TTeamStrategy = class (TSaleStrategy)
  public
    function SalePrice(price:Currency;value:integer):Currency; override;
  end;
  TPriceContext = class (TObject)
  private
    FStrategy: TSaleStrategy;
    procedure SetStrategy(Value: TSaleStrategy);
  public
    function GetPrice(price:Currency;value:integer):Currency;
    property Strategy: TSaleStrategy read FStrategy write SetStrategy;
  end;
 
implementation
 
{TSeasonStrategy }
function TSeasonStrategy.SalePrice(price:Currency;value:integer):Currency;
begin
  //季節銷售策略
  {
  2、3、11月8.5折優惠,
  4、6月9折優惠。
  8、9月9.5折優惠。
  }
  case value of
    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:VIP銀卡 9折優惠
  1:VIP金卡 8折優惠
  2:VIP鉆石卡 7 折優惠
  }
 
  case value of
    0:result:=price*0.9;
    1:result:=price*0.8;
    2:result:=price*0.7;
  end;
end;
 
{TTeamStrategy }
function TTeamStrategy.SalePrice(price:Currency;value:integer):Currency;
begin
  //團隊銷售策略
  {
  3-5人團隊9折優惠;
  6-10人團隊8折優惠;
  11-20人團隊7折優惠;
  20人以上團隊6折優惠。
  }
  result:=price;
  if (value<6) and (value>2) then  result:=price*0.9;
  if (value<11) and (value>5) then  result:=price*0.8;
  if (value<21) and (value>10) then  result:=price*0.7;
  if (value>20) then  result:=price*0.6;
end;
 
{TPriceContext }
function 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單元的源代碼
unit ClientForm;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls,HotelSaleStrategy, ComCtrls,DateUtils;
 
type
  TClient = class(TForm)
    RadioGroup1: TRadioGroup;
    btnCheck: TButton;
    btnExit: TButton;
    dtpDate: TDateTimePicker;
    cmbVIP: TComboBox;
    Label1: TLabel;
    Label2: TLabel;
    cmbPrice: TComboBox;
    edtPrice: TEdit;
    Label3: TLabel;
    edtCount: TEdit;
    Label4: TLabel;
    Label5: TLabel;
    Bevel1: TBevel;
    procedure FormCreate(Sender: TObject);
    procedure btnCheckClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnExitClick(Sender: TObject);
    procedure RadioGroup1Click(Sender: TObject);
  private
    FSeasonStrategy:TSaleStrategy;
    FVIPStrategy:TSaleStrategy;
    FTeamStrategy:TSaleStrategy;
    FPriceSys:TPriceContext;
  public
    { Public declarations }
  end;
 
var
  Client: TClient;
 
implementation
 
 
{$R *.dfm}
 
procedure TClient.FormCreate(Sender: TObject);
begin
  FSeasonStrategy:=TSeasonStrategy.Create;
  FVIPStrategy:=TVIPStrategy.Create;
  FTeamStrategy:=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.DateTime);
      end;
    1:begin
        FPriceSys.Strategy:=FVIPStrategy ;
        i:=cmbVIP.ItemIndex;
      end;
    2:begin
        FPriceSys.Strategy:=FTeamStrategy  ;
        i:=StrToInt(edtCount.Text);
      end;
  end;
  case cmbPrice.ItemIndex of
    0:price:=300 ; //甲類標準間300元
    1:price:=500 ; //乙類標準間500元
    2:price:=800 ; //貴賓間800元
    3:price:=1000; //商務套房1000元
    4:price:=2000; // 豪華套房2000元
  end;
  edtPrice.Text:=CurrToStr(FPriceSys.GetPrice(price,i));
end;
 
procedure TClient.FormDestroy(Sender: TObject);
begin
  FPriceSys.Free;
  FSeasonStrategy.Free;
  FVIPStrategy.Free;
  FTeamStrategy.Free;
end;
 
procedure TClient.btnExitClick(Sender: TObject);
begin
  close;
end;
 
procedure TClient.RadioGroup1Click(Sender: TObject);
begin
  dtpDate.Enabled:=false;
  edtCount.Enabled:=false;
  cmbVIP.Enabled:=false;
  case RadioGroup1.ItemIndex of
    0:dtpDate.Enabled:=true;
    1:cmbVIP.Enabled:=true;
    2:edtCount.Enabled:=true;
  end;
end;
 
end.
1‑7優惠房價查詢模塊的實際運行界面

1.4                         實踐小結

通過前面范例的演示和剖析,我們進一步討論策略模式如下:
·           策略模式提供了管理算法集的辦法。策略類的層次結構為TContext定義了一系列的可供重用的算法或行為。TStrategy基類析取出這些算法中的公共功能,派生類通過繼承豐富了算法的差異和種類,又避免了重復的代碼。
·           如果不將算法和使用算法的上下文分開,直接生成一個包含算法的TContext類的派生類,給它以不同的行為,這將會把行為寫死到TContext中,而將算法的實現與TContext的實現混合起來,從而使TContext難以理解、難以維護和難以擴展。最后得到一大堆相關的類, 它們之間的唯一差別是它們所使用的算法。顯然,類的繼承關系是強關聯,繼承關系無法動態地改變算法;而對象的合成關系是弱關聯,通過組合策略類對象,使得算法可以獨立于使用算法的環境(TContext)而獨立演化。
·           使用策略模式可以對大量使用條件分支語句的程序代碼進行重構。當不同的行為堆砌在一個類中時,很難避免使用條件語句來選擇合適的行為。將行為封裝在一個個獨立的策略類中消除了這些條件語句。
·           過多的算法可能會導致策略對象的數目很大。為了減少系統開銷,通??梢园岩蕾囉谒惴ōh境的狀態保存在客戶端,而將TStrategy實現為可供各客戶端共享的無狀態的對象。任何外部的狀態都由TContext維護。TContext在每一次對TStrategy對象的請求中都將這個狀態傳遞過去。比如范例程序中,我將TSeasonStrategy的外部狀態入住月份、TVIPStrategy的外部狀態VIP卡的種類、TTeamStrategy的外部狀態團隊人數都保存在客戶端,并通過TPriceContext將這些狀態傳遞給銷售策略類。這樣做的好處是銷售策略類變成無狀態的了,它們同時可以被客房結算模塊等其他模塊共享。
·           無論各個具體策略實現的算法是簡單還是復雜, 它們都共享TStrategy定義的接口。因此很可能某些具體策略不會都用到所有通過這個接口傳遞給它們的信息。如果我在范例程序中把TSaleStrategy的接口設計成這樣:
SalePrice(price:Currency;Month:integer;VIP:integer;
                                                 Count:integer):Currency;

其中的一些參數永遠不會被某些具體銷售策略類用到。這就意味著有時TContext會創建和初始化一些永遠不會用到的參數。如果存在這樣問題,又無法使用范例程序中的技巧,那么只能在TStrategy和TContext之間采取緊耦合的方法。


更多相關文章和示例程序源代碼可以到作者網站下載:http://www.liu-yi.net


上一篇:在Delphi中如何維護COM+的狀態信息

下一篇:Delphi7目錄結構----初學者參考

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

主站蜘蛛池模板: 亚洲网站在线播放 | 伊人干综合 | 国产精品久久久久久福利一牛影视 | 免费一区 | 91手机精品视频 | 在线小视频 | 国产不卡在线播放 | 黄色毛片视频在线观看 | 欧美久久久久 | 欧美午夜网 | 亚洲蜜桃精久久久久久久 | 91成人免费在线视频 | 亚洲精品www久久久久久广东 | 青青草国产成人av片免费 | 精东粉嫩av免费一区二区三区 | 成人一区视频 | 成人在线免费 | 欧美日韩久久久 | 一区二区三区免费看 | 天天操天天拍 | 特级黄一级播放 | 国产精品视频男人的天堂 | 九九热这里 | 精品久久久久久久久久久久久久 | 欧美精品在线观看免费 | 欧美日一区二区 | 久久国产精品免费视频 | 狠狠躁日日躁夜夜躁影院 | 精品国产乱码久久久久久1区2区 | 成人免费在线观看 | 精品国产乱码久久久久久88av | 久久久免费电影 | 亚洲成人av在线 | 日韩不卡| 久久精品久久久久久久久久久久久 | 色视频网站在线观看 | 污网站在线免费 | 中文字幕在线一区观看 | 激情五月婷婷在线 | 日韩手机在线视频 | 蜜桃av一区二区三区 |