Modo de estratégia de programação em modo Delphi (continuação)
Liu Yi
1.3 Aplicação do modelo estratégico no sistema de gestão hoteleira
Nos sistemas de gestão hoteleira, normalmente o preço de um quarto não é estático. Deverão existir diferentes estratégias de vendas para a época baixa e época alta do alojamento, clientes antigos e novos clientes, hóspedes individuais e grupos. Obviamente, a estratégia de vendas determina a oferta. No entanto, o sistema de cotação baseado na estratégia de vendas não pode estar vinculado a um cliente específico, pois somente tornando independente o sistema de cotação baseado na estratégia de vendas é que a sua reutilização e manutenção podem ser garantidas. Por exemplo: por um lado, um sistema de cotação atende às necessidades de múltiplos clientes, como consulta de tarifas preferenciais e liquidação de quartos, por outro lado, atende às necessidades de ajuste constante de novas estratégias de vendas. . Para os requisitos de design acima, é melhor escolher o modo estratégico. O padrão Strategy permite alterações de algoritmo independentemente do cliente que o utiliza. O programa de amostra é um módulo de consulta de preços de habitação preferencial baseado no modelo de estratégia, que inclui um sistema de cotação baseado na estratégia de vendas e uma interface de consulta de preços de habitação preferencial. É claro que a interface de consulta de preços preferenciais é apenas um dos clientes do sistema de cotação, e o sistema de cotação também pode ser utilizado por outros clientes. O design do módulo de consulta de preços preferenciais é mostrado na Figura 1-6. Inclui: · Classe de estratégia de vendas TSaleStrategy, que é uma classe base abstrata para classes específicas de estratégia de vendas. · 3 categorias específicas de estratégia de vendas: TVipStrategy (estratégia de vendas com cartão VIP), TTeamStrategy (estratégia de vendas em equipe), TSeasonStrategy (estratégia de vendas sazonais). · Classe de cotação TPRiceContext, que é o contexto neste padrão de estratégia e contém uma referência a TStrategy. · A classe de cliente TClient é uma classe de formulário, que é a interface para consulta de preços de casas. Figura 1-6 O programa de exemplo 1-1 do módulo de consulta de tarifa preferencial com base no padrão de estratégia é o código-fonte da unidade HotelSaleStrategy. Esta unidade contém a lógica de negócios do sistema de cotação com base na estratégia de vendas e é implementada usando o. padrão de estratégia. Como classe base abstrata de estratégia de vendas, TSaleStrategy visa fornecer uma interface comum. A função abstrata virtual SalePrice é uma dessas interfaces. Como as três estratégias de vendas específicas são formuladas com base na temporada, no cartão VIP e no tamanho da equipe, o design dos parâmetros da interface da classe base SalePrice deve atender às diferentes necessidades das três classes derivadas. A função SalePrice de TSaleStrategy é declarada da seguinte forma: function SalePrice(price:Currency;value:integer):Currency Seu primeiro parâmetro representa o preço fixo de entrada e o segundo parâmetro representa as condições preferenciais de entrada; para diferentes classes derivadas. Na estratégia de vendas sazonal TSeasonStrategy, este parâmetro é expresso como o mês de check-in; na estratégia de vendas do cartão VIP TVIPStrategy, este parâmetro é expresso como o tipo de cartão VIP na estratégia de vendas da equipe TTeamStrategy; número de pessoas na equipe. Descobrimos que todos esses parâmetros podem usar tipos inteiros, portanto, na classe base, um parâmetro de valor é usado de maneira inteligente para resolver os diferentes requisitos de parâmetro da classe derivada. Desta forma, TPriceContext pode colocar dados diretamente em parâmetros e passá-los para diferentes operações de estratégia de vendas, evitando redundância de parâmetros. {TPriceContext }função TPriceContext.GetPrice(price:Currency;value:integer):Currency;begin result:=Strategy.SalePrice(price,value);end;TPriceContext desempenha um papel contextual neste modo de estratégia e é responsável por referenciar as vendas estratégia Diferentes instâncias do objeto chamam a interface SalePrice para configurar dinamicamente o algoritmo de desconto específico e retornar o preço de venda real. Devido à intermediação do TPriceContext, o cliente não precisa saber como a estratégia de vendas específica é implementada da mesma forma, quando a estratégia de vendas for atualizada e ajustada, não terá impacto no programa do cliente; Programa de exemplo 1-1 Código fonte da unidade HotelSaleStrategy HotelSaleStrategy;interface usa SysUtils, Windows, Mensagens, Classes, Gráficos, Controles, Formulários, Diálogos;tipo TSaleStrategy = classe (TObject) função pública SalePrice(preço:Moeda;valor:inteiro): Moeda ; virtual; fim abstrato; SalePrice(preço:Moeda;valor:inteiro):Moeda override; fim TVIPStrategy = classe (TSaleStrategy) função pública; SalePrice(preço:Moeda;valor:inteiro):Moeda override; (TObject) private FStrategy: TSaleStrategy; procedimento SetStrategy(Valor: TSaleStrategy); função pública GetPrice(price:Currency;value:integer):Currency property Strategy: TSaleStrategy read FStrategy write SetStrategy;implementação{TSeasonStrategy }função; TSeasonStrategy.SalePrice(price:Currency;value:integer):Currency;begin //Estratégia de vendas sazonais {15% de desconto em fevereiro, março e novembro, 10% de desconto em abril e junho. 8. Desconto de 9,5% em setembro. } valor do caso de 2,3,11:resultado:=preço*0,85; 4,6:resultado:=preço*0,9; TVIPStrategy }função TVIPStrategy.SalePrice(preço:Moeda;valor:inteiro):Moeda;begin //Estratégia de vendas do cartão VIP{ 0: 10% de desconto para Cartão VIP Silver 1: 20% de desconto para Cartão VIP Gold 2: 30% de desconto para Cartão VIP Diamond} valor da caixa 0:resultado:=preço*0,9; :resultado: =preço*0,7; fim;fim;{TTeamStrategy }função TTeamStrategy.SalePrice(price:Currency;value:integer):Currency;begin //Estratégia de vendas da equipe {10% de desconto para uma equipe de 3 a 5 pessoas; 20% de desconto para uma equipe de 6 a 10 pessoas; uma equipe de 11 a 20 pessoas 20 40% de desconto para grupos de mais de 1 pessoa; } resultado:=preço; if (valor<6) e (valor>2) então resultado:=preço se (valor<11) e (valor>5) então resultado:=preço*0,8; 21) e (valor>10) então resultado:=preço*0,7; if (valor>20) então resultado:=preço*0,6;end;{TPriceContext }função TPriceContext.GetPrice(preço:Moeda;valor:inteiro):Moeda;início resultado:=Strategy.SalePrice(preço,valor);fim;procedimento TPriceContext.SetStrategy(Valor: TSaleStrategy);begin FStrategy:=Valor;fim;fim. O programa cliente do módulo de consulta de tarifa de quarto preferencial é mostrado no Exemplo de Programa 1-2. O programa disponibiliza uma interface de seleção do usuário para que o solicitante possa escolher um plano preferencial. Depois de selecionar as condições preferenciais e tarifas públicas, clique no botão “Verificar Tarifas Preferenciais” para obter as tarifas com desconto. O efeito real da operação é mostrado na Figura 1-7. Programa de exemplo 1-2 Unidade de código-fonte da unidade ClientForm Interfaceusa Windows, Mensagens, SysUtils, Variantes, Classes, Gráficos, Controles, Formulários, Diálogos, StdCtrls, ExtCtrls, HotelSaleStrategy, ComCtrls,DateUtils; TRadioGroup; TButton: TButton; dtpDate: TEdit; TLabel: TLabel; TLabel; procedimento FormCreate(Remetente: TObject); procedimento btnCheckClick(Remetente: TObject); procedimento FormDestroy(Remetente: TObject); procedimento FTeamStrategy:TSaleStrategy; TPriceContext; { Declarações públicas } end;var Cliente: TClient;implementação{$R *.dfm}procedimento TClient.FormCreate(Sender: TObject);begin FSeasonStrategy:=TSeasonStrategy.Create; ; FPriceSys:=TPriceContext.Create;end;procedure TClient.btnCheckClick(Sender: TObject);var i:integer;Currency;begin case RadioGroup1.ItemIndex of 0:begin FPriceSys.Strategy:=FSeasonStrategy ; .DateTime); fim 1:início FPriceSys.Strategy:=FVIPStrategy ;=cmbVIP.ItemIndex; end 2:begin FPriceSys.Strategy:=FTeamStrategy ; 300; //Quarto padrão classe A custa 300 yuans 1:preço:=500; //Quarto padrão classe B custa 500 yuans 2:preço:=800; //Quarto VIP custa 800 yuans 3:preço:=1000; //Suite executiva custa 1.000 yuans 4:preço:=2.000; yuanend; edtPrice .Text:=CurrToStr(FPriceSys.GetPrice(preço,i));end;procedimento TClient.FormDestroy(Sender: TObject); iniciar FPriceSys.Free; FSeasonStrategy.Free; FVIPStrategy.Free;end; edtCount.Enabled:=false; cmbVIP.Enabled:=false; caso RadioGroup1.ItemIndex de 0:dtpDate.Enabled:=true; final. Figura 1-7 A interface de execução real do módulo de consulta de preço preferencial.
1.4 Resumo da prática
Através da demonstração e análise dos exemplos anteriores, discutiremos mais detalhadamente o padrão de estratégia da seguinte forma: · O padrão de estratégia fornece uma maneira de gerenciar um conjunto de algoritmos. A hierarquia de classes de estratégia define uma série de algoritmos ou comportamentos reutilizáveis para TContext. A classe base TStrategy extrai as funções comuns nesses algoritmos, e as classes derivadas enriquecem as diferenças e tipos de algoritmos por meio de herança e evitam a duplicação de código. · Se você não separar o algoritmo do contexto no qual o algoritmo é usado, e gerar diretamente uma classe derivada da classe TContext que contém o algoritmo, e fornecer a ele comportamentos diferentes, isso codificará o comportamento em TContext, e separar a implementação do algoritmo do TContext As implementações são confusas, tornando o TContext difícil de entender, manter e estender. O resultado final é um monte de classes relacionadas, a única diferença entre elas é o algoritmo que usam. Obviamente, o relacionamento de herança de classes é uma associação forte, e o relacionamento de herança não pode alterar dinamicamente o algoritmo, enquanto o relacionamento de composição de objetos é uma associação fraca. Ao combinar objetos de classe de estratégia, o algoritmo pode evoluir independentemente do ambiente (TContext). em que o algoritmo é usado. · Use o padrão de estratégia para refatorar códigos de programa que usam um grande número de instruções de desvio condicional. Quando diferentes comportamentos são empilhados em uma classe, é difícil evitar o uso de instruções condicionais para selecionar o comportamento apropriado. Encapsular o comportamento em classes de políticas separadas elimina essas declarações condicionais. · Demasiados algoritmos podem resultar num grande número de objectos políticos. Para reduzir a sobrecarga do sistema, o estado que depende do ambiente do algoritmo geralmente pode ser salvo no cliente, e o TStrategy é implementado como um objeto sem estado que pode ser compartilhado por vários clientes. Qualquer estado externo é mantido pelo TContext. TContext passa esse estado em cada solicitação para o objeto TStrategy. Por exemplo, no programa de amostra, eu salvo o mês de check-in do status externo do TSeasonStrategy, o tipo de cartão VIP do status externo do TVIPStrategy e o tamanho da equipe de status externo do TTeamStrategy no cliente e passo esses status para a classe de estratégia de vendas por meio do TPriceContext. A vantagem disso é que a classe de estratégia de vendas se torna apátrida e pode ser compartilhada por outros módulos, como o módulo de liquidação de quartos. · Independentemente de o algoritmo implementado por cada estratégia específica ser simples ou complexo, todos compartilham a interface definida pela TStrategy. Portanto, é provável que algumas políticas específicas não utilizem todas as informações que lhes são transmitidas através desta interface. Se eu projetar a interface do TSaleStrategy assim no programa de exemplo:
SalePrice(preço:Moeda;Mês:inteiro;VIP:inteiro;
Contagem:inteiro):Moeda;
Alguns desses parâmetros nunca serão utilizados por determinadas classes de estratégia de vendas. Isso significa que às vezes o TContext criará e inicializará parâmetros que nunca serão usados. Se houver tal problema e você não puder usar as técnicas do programa de exemplo, você só poderá adotar um método fortemente acoplado entre TStrategy e TContext.
Mais artigos relacionados e exemplos de códigos-fonte de programas podem ser baixados do site do autor: http://www.liu-yi.net