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?
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?
Respostas:
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:
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.
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.A diferença reside simplesmente em que eles resolvem problemas diferentes:
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.
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:
Vamos comparar Estado e Estratégia.
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á.
State possui a seguinte estrutura de classe UML:
A estratégia possui a seguinte estrutura de classes UML:
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.
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:
Supondo que as subclasses decidam a transição de estado (retornando o próximo objeto de estado), a dinâmica se parece com isso:
Para mostrar a dinâmica da estratégia , é útil emprestar um exemplo real .
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.
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.
Considere um sistema de IVR (resposta interativa de voz) que lida com chamadas de clientes. Você pode programá-lo para lidar com clientes em:
Para lidar com essa situação, você pode usar um Padrão de Estado .
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:
O padrão de estratégia decide ' como ' executar alguma ação e o padrão de estado decide ' quando ' executá-las.
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.
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.
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 :
Características principais:
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:
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 :
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.
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 )
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.
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.
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.
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.
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.
'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.