Delphi模式编程之策略模式(续)
刘 艺
1.3 策略模式在酒店管理系统中的应用
在酒店管理系统中,通常客房的价格不是一成不变的。对于住宿的淡季和旺季、老客户和新客户、散客和团队,都应该有不同的销售策略。显然,销售策略决定了报价。但是基于销售策略的报价体系又不能绑定于某一具体的客户端,因为只有把基于销售策略的报价体系独立出来,才能保证其重用性和可维护性。比如:一种报价体系一方面满足了优惠房价查询、客房结算等多个客户端的使用,另一方面又满足了不断调整的新销售策略的需求,这才算真正做到了重用性和可维护性。
对于以上的设计要求,选用策略模式是最好不过了。策略模式能够让算法变化独立于使用它的客户端。范例程序是一个基于策略模式的优惠房价查询模块,它包括一个基于销售策略的报价体系和一个优惠房价查询界面。当然,优惠房价查询界面只是该报价体系的客户端之一,报价体系亦可被其他客户端使用。
优惠房价查询模块的设计如图 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(S [1] [2] 下一页 没有相关教程
|