ender: 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)而独立演化。
· 使用策略模式可以对大量使用条件分支语句的程序代码进行重构。当不同的行为堆砌在一个类中时,很难避免使用条件语句来选择合适的行为。将行为封装在一个个独立的策略类中消除了这些条件语句。
· 过多的算法可能会导致策略对象的数目很大。为了减少系统开销,通常可以把依赖于算法环境的状态保存在客户端,而将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
上一页 [1] [2] 没有相关教程
|