Qual é a diferença entre o padrão de design da estratégia e o padrão de design do estado?

219

Quais são as diferenças entre o padrão de design da estratégia e o padrão de design do estado? Eu estava analisando alguns artigos na Web, mas não conseguia distinguir claramente a diferença.

Alguém pode explicar a diferença nos termos dos leigos?

Chin Tser
fonte
Com base nas respostas aqui e em minhas próprias observações, parece que as implementações são em grande parte (embora não inteiramente) as mesmas. Pelo contrário, a diferença é principalmente uma das intenções: estamos tentando adaptar o comportamento, com base em nosso estado (padrão de estado) ou com base em outra coisa (padrão de estratégia). Muitas vezes, outra coisa é "o que o cliente escolhe", por injeção.
Timo

Respostas:

139

Honestamente, os dois padrões são bastante semelhantes na prática, e a diferença que define entre eles tende a variar dependendo de quem você pergunta. Algumas escolhas populares são:

  • Os estados armazenam uma referência ao objeto de contexto que os contém. Estratégias não.
  • Os estados podem se substituir (IE: alterar o estado do objeto de contexto para outra coisa), enquanto as estratégias não o são.
  • As estratégias são passadas para o objeto de contexto como parâmetros, enquanto os Estados são criados pelo próprio objeto de contexto.
  • As estratégias lidam apenas com uma tarefa única e específica, enquanto os Estados fornecem a implementação subjacente para tudo (ou quase tudo) que o objeto de contexto faz.

Uma implementação "clássica" corresponderia a Estado ou Estratégia para todos os itens da lista, mas você encontra híbridos que possuem misturas de ambos. Se um em particular é mais o Estado-y ou a Estratégia-y é, em última análise, uma questão subjetiva.


fonte
6
Se você está contando o GoF como uma das escolhas populares, eles discordam que os Estados são necessariamente criados pelo contexto (podem ser criados pelo cliente e transmitidos ao contexto, assim como na Estratégia).
Will Hardwick-Smith
109
  • O padrão da estratégia é realmente sobre ter uma implementação diferente que realize (basicamente) a mesma coisa, para que uma implementação possa substituir a outra conforme a estratégia exigir. Por exemplo, você pode ter algoritmos de classificação diferentes em um padrão de estratégia. Os chamadores do objeto não mudam com base em qual estratégia está sendo empregada, mas, independentemente da estratégia, a meta é a mesma (classifique a coleção).
  • O padrão do Estado consiste em fazer coisas diferentes com base no estado, deixando o chamador aliviado do ônus de acomodar todos os estados possíveis. Portanto, por exemplo, você pode ter um getStatus()método que retornará status diferentes com base no estado do objeto, mas o responsável pela chamada do método não precisa ser codificado de maneira diferente para contabilizar cada estado potencial.
Yishai
fonte
1
mas quem muda a estratégia no padrão de estratégia?
Noor
1
@ Normal, geralmente é um parâmetro ou campo de algum tipo. O código do chamador real não é alterado com base em uma mudança na estratégia.
Yishai
4
@ Bom, sim, mas em qualquer padrão de estratégia que eu possa pensar agora, será uma decisão inicial que não mudará no meio.
Yishai 8/03/13
2
Estou com o mesmo problema, Estado ou Estratégia, acho que a diferença em poucas palavras é: Estado, comportamento é autodeterminado, estratégia, comportamento é determinado pelo chamador.
Rene MF
1
No aplicativo de comércio eletrônico, se um desconto extra precisar ser aplicado na época festiva, será um padrão de design estadual. A lógica da taxa de desconto real pode ser aplicada com o padrão de design da estratégia, se houver mais de uma maneira de chegar a esse número.
Bharathkumar V
85

A diferença reside simplesmente em que eles resolvem problemas diferentes:

  • O padrão State lida com o que (estado ou tipo) um objeto é (in) - ele encapsula o comportamento dependente do estado, enquanto
  • o padrão de estratégia lida com a maneira como um objeto executa uma determinada tarefa - ele encapsula um algoritmo.

As construções para alcançar esses diferentes objetivos são, no entanto, muito semelhantes; ambos os padrões são exemplos de composição com delegação.


Algumas observações sobre suas vantagens:

Ao usar o padrão State, a classe state-holding (context) é liberada do conhecimento de qual estado ou tipo é e quais estados ou tipos estão disponíveis. Isso significa que a classe segue o princípio de projeto aberto-fechado (OCP): a classe é fechada para alterações em quais estados / tipos existem, mas os estados / tipos estão abertos a extensões.

Ao usar o padrão Estratégia, a classe de uso do algoritmo (contexto) é aliviada do conhecimento de como executar uma determinada tarefa (- o "algoritmo"). Este caso também cria uma aderência ao OCP; a classe está fechada para alterações sobre como executar esta tarefa, mas o design é muito aberto a adições de outros algoritmos para resolver essa tarefa.
Isso provavelmente também melhora a aderência da classe de contexto ao princípio de responsabilidade única (SRP). Além disso, o algoritmo se torna facilmente disponível para reutilização por outras classes.

Ulf Åkerstedt
fonte
42

Alguém pode por favor explicar nos termos do leigo?

Os padrões de design não são realmente conceitos "leigos", mas tentarei deixar o mais claro possível. Qualquer padrão de design pode ser considerado em três dimensões:

  1. O problema que o padrão resolve;
  2. A estrutura estática do padrão (diagrama de classes);
  3. A dinâmica do padrão (diagramas de sequência).

Vamos comparar Estado e Estratégia.

Problema que o padrão resolve

O estado é usado em um dos dois casos [livro GoF p. 306] :

  • O comportamento de um objeto depende do seu estado e ele deve mudar seu comportamento no tempo de execução, dependendo desse estado.
  • As operações possuem instruções condicionais grandes e com várias partes que dependem do estado do objeto. Esse estado geralmente é representado por uma ou mais constantes enumeradas. Freqüentemente, várias operações conterão essa mesma estrutura condicional. O padrão State coloca cada ramo da condicional em uma classe separada. Isso permite tratar o estado do objeto como um objeto por si só, que pode variar independentemente de outros objetos.

Se você quiser ter certeza de que realmente tem o problema que o padrão State resolve, poderá modelar os estados do objeto usando uma máquina de estados finitos . Você pode encontrar um exemplo aplicado aqui .

Cada transição de estado é um método na interface State. Isso implica que, para um design, você precisa ter bastante certeza das transições de estado antes de aplicar esse padrão. Caso contrário, se você adicionar ou remover transições, será necessário alterar a interface e todas as classes que a implementam.

Pessoalmente, não achei esse padrão tão útil. Você sempre pode implementar máquinas de estado finito usando uma tabela de pesquisa (não é uma maneira OO, mas funciona muito bem).

A estratégia é usada para o seguinte [livro GoF p. 316] :

  • muitas classes relacionadas diferem apenas em seu comportamento. As estratégias fornecem uma maneira de configurar uma classe com um dos muitos comportamentos.
  • você precisa de diferentes variantes de um algoritmo. Por exemplo, você pode definir algoritmos que refletem diferentes compensações de espaço / tempo. Estratégias podem ser usadas quando essas variantes são implementadas como uma hierarquia de classes de algoritmos [HO87].
  • um algoritmo usa dados que os clientes não deveriam conhecer. Use o padrão Estratégia para evitar a exposição de estruturas de dados complexas e específicas de algoritmos.
  • uma classe define muitos comportamentos e estes aparecem como várias instruções condicionais em suas operações. Em vez de muitos condicionais, mova ramificações condicionais relacionadas para sua própria classe Strategy.

O último caso de onde aplicar a estratégia está relacionado a uma refatoração conhecida como Substituir condicional por polimorfismo .

Resumo: Estado e Estratégia resolvem problemas muito diferentes. Se o seu problema não puder ser modelado com uma máquina de estados finitos, provavelmente o padrão de estado não é apropriado. Se o seu problema não for encapsular variantes de um algoritmo complexo, a Estratégia não se aplicará.

Estrutura estática do padrão

State possui a seguinte estrutura de classe UML:

Diagrama de classe PlantUML do Padrão de Estado

A estratégia possui a seguinte estrutura de classes UML:

Diagrama de classe PlantUML do Padrão de Estratégia

Resumo: em termos de estrutura estática, esses dois padrões são praticamente idênticos. De fato, ferramentas de detecção de padrões como esta consideram que " a estrutura dos [...] padrões é idêntica, proibindo sua distinção por um processo automático (por exemplo, sem se referir a informações conceituais) " .

Entretanto, pode haver uma grande diferença se o ConcreteStates decidir as transições de estado (consulte as associações " pode determinar " no diagrama acima). Isso resulta em acoplamento entre estados concretos. Por exemplo (consulte a próxima seção), o estado A determina a transição para o estado B. Se a classe Context decidir a transição para o próximo estado concreto, essas dependências desaparecerão.

Dinâmica do padrão

Conforme mencionado na seção Problema acima, State implica que o comportamento muda no tempo de execução, dependendo de algum estado de um objeto. Portanto, a noção de transição de estado se aplica, conforme discutido com a relação da máquina de estados finitos . [GoF] menciona que as transições podem ser definidas nas subclasses ConcreteState ou em um local centralizado (como um local baseado em tabela).

Vamos assumir uma simples máquina de estados finitos:

Diagrama de transição de estados PlantUML com dois estados e uma transição

Supondo que as subclasses decidam a transição de estado (retornando o próximo objeto de estado), a dinâmica se parece com isso:

Diagrama de sequência do PlantUML para transições de estado

Para mostrar a dinâmica da estratégia , é útil emprestar um exemplo real .

Diagrama de sequência do PlantUML para transições de estratégia

Resumo : Cada padrão usa uma chamada polimórfica para fazer algo, dependendo do contexto. No padrão de estado, a chamada polimórfica (transição) geralmente causa uma alteração no próximo estado . No padrão Estratégia, a chamada polimórfica normalmente não muda o contexto (por exemplo, pagar com cartão de crédito uma vez não implica que você pagará com PayPal na próxima vez). Novamente, a dinâmica do padrão de estado é determinada por sua máquina de estados fininte correspondente , que (para mim) é essencial para corrigir a aplicação desse padrão.

Fuhrmanator
fonte
Essa resposta foi muito útil para fazer-me distinguir a diferença. O argumento da máquina de estado parece ser IMHO pertinente. Na verdade, isso resume as respostas acima de uma maneira teórica da ciência da computação.
medunes
Esta resposta é muito útil, para mim é a melhor.
Chofoteddy
25

O Padrão de Estratégia envolve mover a implementação de um algoritmo de uma classe de hospedagem e colocá-lo em uma classe separada. Isso significa que a classe host não precisa fornecer a implementação de cada algoritmo, o que provavelmente levará a códigos impuros.

Os algoritmos de classificação são geralmente usados ​​como exemplo, pois todos fazem o mesmo tipo de coisa (classificação). Se cada algoritmo de classificação diferente for colocado em sua própria classe, o cliente poderá escolher facilmente qual algoritmo usar e o padrão fornecerá uma maneira fácil de acessá-lo.

O Padrão de Estado envolve a alteração do comportamento de um objeto quando o estado do objeto é alterado. Isso significa que a classe host não fornece a implementação de comportamento para todos os diferentes estados em que pode estar. A classe host geralmente encapsula uma classe que fornece a funcionalidade necessária em um determinado estado e alterna para uma classe diferente quando o estado muda.

Ryan Spears
fonte
16

Considere um sistema de IVR (resposta interativa de voz) que lida com chamadas de clientes. Você pode programá-lo para lidar com clientes em:

  • Dias de trabalho
  • Feriados

Para lidar com essa situação, você pode usar um Padrão de Estado .

  • Feriado : a IVR simplesmente responde dizendo que 'as chamadas podem ser feitas apenas em dias úteis das 9:00 às 17:00 '.
  • Dias úteis : responde conectando o cliente a um executivo de atendimento ao cliente.

Esse processo de conexão de um cliente a um executivo de suporte pode ser implementado usando um Padrão de Estratégia em que os executivos são escolhidos com base em:

  • Round Robin
  • Menos Utilizado Recentemente
  • Outros algoritmos baseados em prioridade

O padrão de estratégia decide ' como ' executar alguma ação e o padrão de estado decide ' quando ' executá-las.

Murali Mohan
fonte
Esta é uma excelente resposta e subestimada. Mas, seria útil mencionar por que existem muitos algoritmos no seu exemplo. Por exemplo, o algoritmo é escolhido com base na preferência da empresa de call center. Também ajudaria se houvesse algoritmos mais simples ou triviais em sua lista para aqueles que não conhecem RR ou LRU. Por exemplo: o cliente de longa data obtém maior prioridade, o cliente que mais esperou recebe maior prioridade. Obrigado !
MasterJoe2
14

A estratégia representa objetos que "fazem" algo, com os mesmos resultados iniciais e finais, mas internamente usando metodologias diferentes. Nesse sentido, eles são análogos a representar a implementação de um verbo. O padrão de estado OTOH usa objetos que "são" algo - o estado de uma operação. Embora eles também possam representar operações nesses dados, eles são mais análogos à representação de um substantivo do que de um verbo e são adaptados para máquinas de estado.

zzzeek
fonte
11

Estratégia: a estratégia é fixa e geralmente consiste em várias etapas. (A classificação constitui apenas uma etapa e, portanto, é um exemplo muito ruim, pois é muito primitiva para entender o propósito desse padrão). Sua rotina "principal" da estratégia está chamando alguns métodos abstratos. Por exemplo, "Enter Room Strategy", "main-method" é goThroughDoor (), que se parece com: approachDoor (), if (locked ()) openLock (); porta aberta(); enterRoom (); virar(); porta fechada(); if (wasLocked ()) lockDoor ();

Agora, as subclasses desse "algoritmo" geral para mover de uma sala para outra através de uma possível porta trancada podem implementar as etapas do algoritmo.

Em outras palavras, a subclasse da estratégia não altera os algoritmos básicos, apenas etapas individuais.

QUE ACIMA é um padrão de método de modelo. Agora coloque as etapas que pertencem juntas (desbloqueio / bloqueio e abertura / fechamento) em seus próprios objetos de implementação e delegar a eles. Por exemplo, uma fechadura com uma chave e uma fechadura com um cartão de código são dois tipos de fechaduras. Delegue da estratégia para os objetos "Etapa". Agora você tem um padrão de estratégia.

Um padrão de estado é algo completamente diferente.

Você tem um objeto de quebra e o objeto quebrado. O embrulhado é o "estado". O objeto de estado é acessado apenas através de seu wrapper. Agora você pode alterar o objeto agrupado a qualquer momento, assim o wrapper parece alterar seu estado ou mesmo sua "classe" ou tipo.

Por exemplo, você tem um serviço de logon. Ele aceita um nome de usuário e uma senha. Ele possui apenas um método: logon (String userName, String passwdHash). Em vez de decidir por si próprio se um logon é aceito ou não, ele delega a decisão para um objeto de estado. Esse objeto de estado geralmente apenas verifica se a combinação usuário / aprovação é válida e executa um logon. Mas agora você pode trocar o "Verificador" por um que apenas permita que usuários privilegiados façam logon (durante o período de manutenção, por exemplo) ou por um que não permita que ninguém faça logon. Isso significa que o "verificador" expressa o "status de logon" do sistema.

A diferença mais importante é: quando você escolhe uma estratégia, fica com ela até terminar. Isso significa que você chama seu "método principal" e, enquanto ele estiver em execução, você nunca muda a estratégia. OTOH em uma situação de padrão de estado durante o tempo de execução do seu sistema, você muda de estado arbitrariamente, conforme entender.

Angel O'Sphere
fonte
9

O padrão de estratégia é usado quando você possui vários algoritmos para uma tarefa específica e o cliente decide a implementação real a ser usada no tempo de execução.

Diagrama UML do artigo de estratégia padrão do wiki :

insira a descrição da imagem aqui

Características principais:

  1. É um padrão comportamental.
  2. É baseado em delegação.
  3. Ele altera as entranhas do objeto, modificando o comportamento do método.
  4. É usado para alternar entre a família de algoritmos.
  5. Ele altera o comportamento do objeto em tempo de execução.

Consulte este post para obter mais informações e exemplos do mundo real:

Exemplo do mundo real do padrão de estratégia

O padrão de estado permite que um objeto altere seu comportamento quando seu estado interno é alterado

Diagrama UML do artigo do wiki State pattern:

insira a descrição da imagem aqui

Se precisarmos alterar o comportamento de um objeto com base em seu estado, podemos ter uma variável de estado no objeto e usar o bloco de condição if-else para executar ações diferentes com base no estado. O padrão de estado é usado para fornecer uma maneira sistemática e de perda acoplada para alcançar isso por meio de implementações de contexto e estado .

Consulte este artigo do journaldev para obter mais detalhes.

Principais diferenças dos artigos de criação de origens e de journaldev :

  1. A diferença entre Estado e Estratégia está no tempo vinculativo. A Estratégia é um padrão vinculativo, enquanto o Estado é mais dinâmico .
  2. A diferença entre Estado e Estratégia está na intenção. Com a Strategy, a escolha do algoritmo é bastante estável . Com o State, uma alteração no estado do objeto "context" faz com que ele selecione da "paleta" de objetos Strategy .
  3. Contexto contém Estado como instância variável e pode haver múltiplas tarefas cuja implementação pode ser dependente do Estado enquanto na estratégia padrão de estratégia é passado como argumento para o método e contexto objeto não tem qualquer variável para armazená-lo.
Ravindra babu
fonte
5

Na linguagem dos leigos,

no padrão de estratégia, não há estados ou todos eles têm o mesmo estado. Tudo o que temos são maneiras diferentes de executar uma tarefa, como médicos diferentes tratam a mesma doença do mesmo paciente com o mesmo estado de maneiras diferentes.

No Padrão de estado, subjetivamente, existem estados, como o estado atual do paciente (digamos, alta temperatura ou baixa temperatura), com base no qual o próximo curso de ação (prescrição do medicamento) será decidido. E um estado pode levar a outro estado, então existe declarar dependência (composição tecnicamente).

Se tecnicamente tentarmos entendê-lo, com base na comparação de códigos de ambos, podemos perder a subjetividade da situação, porque ambos parecem muito semelhantes.

pkgrocz
fonte
2

Ambos os padrões delegam para uma classe base que possui várias derivadas, mas é apenas no padrão State que essas classes derivadas mantêm uma referência de volta à classe de contexto.

Outra maneira de ver é que o padrão de estratégia é uma versão mais simples do padrão de estado; um sub-padrão, se quiser. Realmente depende se você deseja que os estados derivados mantenham referências de volta ao contexto ou não (ou seja: deseja que eles chamem métodos no contexto).

Para mais informações: Robert C Martin (& Micah Martin) responda a isso em seu livro "Princípios Ágeis, Padrões e Práticas em C #". ( http://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258 )

Adrian K
fonte
2

Essa é uma pergunta bastante antiga, mas ainda assim eu estava procurando as mesmas respostas e foi isso que descobri.

Para o padrão State, vamos considerar um exemplo do botão Medial Player Play. Quando tocamos, ele começa a tocar e conscientiza o contexto de que está tocando. Toda vez que o cliente deseja executar a operação de jogo, ele verifica o estado atual do jogador. Agora, o cliente sabe que o estado do objeto está sendo reproduzido por meio do objeto de contexto, então ele chama o método de ações dos objetos de estado de pausa. A parte do cliente que realiza o estado e em que estado ele precisa executar a ação pode ser automatizada.

https://www.youtube.com/watch?v=e45RMc76884 https://www.tutorialspoint.com/design_pattern/state_pattern.htm

No caso do padrão de estratégia, a organização do diagrama de classes é igual ao padrão de estado. O cliente chega a esse arranjo para fazer alguma operação. Ou seja, em vez dos estados diferentes, existem algoritmos diferentes, por exemplo, análises diferentes que precisam ser executadas no padrão. Aqui, os clientes informam ao contexto o que desejam fazer e o que algoritmo (algoritmo personalizado definido pelos negócios) e, em seguida, realizam isso.

https://www.tutorialspoint.com/design_pattern/strategy_pattern.htm

Ambos implementam o princípio de fechamento aberto, para que o desenvolvedor tenha a capacidade de adicionar novos estados ao padrão de estado e ao novo algoritmo.

Mas a diferença é o que eles usam, que é o padrão de estado usado para executar uma lógica diferente com base no estado do objeto. E em um caso de estratégia lógica diferente.

Ameya
fonte
2

O estado vem com um pouco de dependências nas classes derivadas do estado: como um estado sabe sobre outros estados que o seguem. Por exemplo, o verão vem depois do inverno para qualquer estado da estação ou estado de entrega após o estado do depósito para compras.

Por outro lado, a estratégia não possui dependências como essas. Aqui, qualquer tipo de estado pode ser inicializado com base no tipo de programa / produto.

MH Rahman
fonte
1

A diferença é discutida em http://c2.com/cgi/wiki?StrategyPattern . Eu usei o padrão de estratégia para permitir que diferentes algoritmos sejam escolhidos dentro de uma estrutura geral para análise de dados. Com isso, você pode adicionar algoritmos sem precisar alterar as estruturas gerais e sua lógica.

Um exemplo típico é que você tem uma estrutura para otimizar uma função. A estrutura configura os dados e parâmetros. O padrão de estratégia permite selecionar algoritmos como descidas mais altas, gradientes conjugados, BFGS, etc., sem alterar a estrutura.

peter.murray.rust
fonte
1

O padrão de estratégia e estado tem a mesma estrutura. Se você observar o diagrama de classes UML para ambos os padrões, eles terão exatamente a mesma aparência, mas sua intenção é totalmente diferente. O padrão de design de estado é usado para definir e gerenciar o estado de um objeto, enquanto o padrão de Estratégia é usado para definir um conjunto de algoritmos intercambiáveis ​​e permite que o cliente escolha um deles. Portanto, o padrão de estratégia é um padrão orientado ao cliente, enquanto o Object pode gerenciar o próprio estado.

Rakesh KR
fonte
1

Em resumo, com o padrão de estratégia, podemos definir algum comportamento instantaneamente, com o padrão de estado, podemos ter certeza de que um objeto mudará seu comportamento internamente com a mudança de seu estado.

rastaman
fonte
0

Quando você tem um projeto que pode ser dividido em 2 tarefas:

tarefa 1: você pode usar um dos dois algoritmos diferentes para realizar: alg1, alg2

tarefa 2: você pode usar um dos três algoritmos diferentes para realizar: alg3, alg4, alg5

alg1 e alg2 são intercambiáveis; alg3, alg4 e alg5 são intercambiáveis.

A escolha do algoritmo a ser executado nas tarefas 1 e 2 depende dos estados:

estado 1: você precisa de alg1 na tarefa 1 e alg3 na tarefa 2

estado 2: você precisa de alg2 na tarefa 1 e alg5 na tarefa 2

Seu contexto pode alterar o objeto de estado do estado 1 para o estado 2. Em seguida, sua tarefa seria realizada por alg2 e alg5, em vez de alg1 e alg3.

Você pode adicionar algoritmos mais intercambiáveis ​​para a tarefa 1 ou a tarefa 2. Esse é o padrão de estratégia.

Você pode ter mais estados com combinações diferentes de algoritmos na tarefa 1 e na tarefa 2. O padrão de estado permite alternar de um estado para outro e executar diferentes combinações de algoritmos.

user791961
fonte
0

'Estratégia' é apenas um algoritmo que você pode alterá-lo em diferentes circunstâncias, conforme sua necessidade, e processa algo para você. Ex. você pode escolher como compactar um arquivo. zip ou rar ... em um método.

Mas 'Estado' PODE mudar todo o comportamento do seu objeto, quando ele muda, Mesmo ele pode mudar outros campos ... é por isso que ele tem uma referência ao seu dono. Você deve observar que alterar um campo de objeto pode alterar o comportamento do objeto. Ex. quando você altera State0 para State1 em obj, altera um número inteiro para 10. Portanto, quando chamamos obj.f0 () que faz algum cálculo e usa esse número inteiro, isso afeta o resultado.

Ali Dahaghin
fonte