A herança de contexto, como mostra o exemplo Duck dos Head First Design Patterns, é irrelevante para o padrão de estratégia?

10

No Head First Design Patterns, ele ensina o padrão de estratégia usando um exemplo do Duck, em que diferentes subclasses do Duck podem ser atribuídas a um determinado comportamento em tempo de execução. Pelo meu entendimento, o objetivo do padrão de estratégia é alterar o comportamento de um único objeto em tempo de execução, mas eles estão usando a herança do Duck para alterar o comportamento de vários tipos de Duck.

Padrão de Estratégia

Relevância?

A herança de contexto do Duck é irrelevante para o padrão de estratégia ou a variação de tipos de Duck e também a variação de seus comportamentos é uma boa razão para empregar o padrão de estratégia? As situações em que você precisa variar ambas constituem um bom motivo para usar o padrão de estratégia? Por que eles incluiriam isso como exemplo de padrão de estratégia?

Um exemplo mais simples

Eu poderia simplificar ainda mais este exemplo, tendo apenas uma classe Duck (sem classes derivadas)? Em seguida, ao implementar um objeto duck, é possível atribuir comportamentos diferentes com base em determinadas circunstâncias que não dependem de seu próprio tipo de objeto. Por exemplo: FlyBehavior muda com base no clima ou QuackBehavior muda com base na hora do dia ou na fome de um pato. Sei que isso resolveria um problema diferente daquele do livro, mas o que estou procurando é um exemplo relevante de padrão de estratégia para recorrer.

Meu exemplo acima também constituiria o padrão de estratégia?

Editar:

Consegui encontrar dois exemplos mais simples de padrões de estratégia que aderem mais estritamente a serem apenas padrões de estratégia sem herança de contexto: Hunter.java e solver.py .

Korey Hinton
fonte

Respostas:

7

Sim, acho que você está no caminho certo. A classe que usa o padrão de estratégia não precisa ser uma subclasse. O padrão de estratégia é uma alternativa à herança para reutilização de código. Isso volta à comparação ainda mais ampla de herança versus composição.

Em Design Patterns: Elements of Reusable OOP, você usaria o padrão de estratégia para

  • Evite uma explosão de subclasses (devido a combinações de comportamentos)
  • Se você precisar trocar o comportamento em tempo de execução

Se você usasse herança para implementar comportamentos Quack and Fly, resultaria em todas essas subclasses para representar todas as combinações de comportamentos.

  • FlyableQuackableDuck
  • FlyableSqeakableDuck
  • FlyableMuteDuck
  • NoFlyQuackableDuck
  • NoFlySqueakableDuck
  • NoFlyMuteDuck

Ter tantas subclasses torna mais difícil a manutenção, razão pela qual o padrão de estratégia é favorecido nesse caso. Você só precisa de duas propriedades que encapsulam Flyability e Quackability e pode combiná-las e combiná-las sem criar novas classes.

Você também mencionou o benefício em tempo de execução, caso o tempo alterasse a propriedade Fly do pato poderia ser substituída por um objeto NoFly devido às condições.

Isso é consistente com o conselho de favorecer a composição sobre a herança, quando possível.

Despertar
fonte
1

Eu poderia simplificar ainda mais este exemplo, tendo apenas uma classe Duck (sem classes derivadas)? Em seguida, ao implementar um objeto duck, é possível atribuir comportamentos diferentes com base em determinadas circunstâncias que não dependem de seu próprio tipo de objeto.

Certamente. Para inspiração, dê uma olhada em Head First Object-Oriented Analysis and Design . Há um "Rick's Guitars" mostrando uma explosão de subclasses de instrumentos (musicais) . Para remediar isso, todo esse comportamento variável é envolvido em uma classe "especificação", observando o princípio de encapsular o que varia .

Fábrica abstrata - construção baseada em contexto

Aqui está o padrão . BTW, observe que ele usa a própria estratégia.

Focando no conceito, não na implementação ... Você pode ter um "WeatherFactory" que constrói objetos de especificação com base em condições de sol ou chuva, etc.

Você pode ter "fábricas de fábricas" para construir essas coisinhas "NoFlyInFogQuackableMallard". E, de fato, é disso que trata o padrão Abstract Factory. Então, talvez um DuckFactory faça tipos gerais de patos e, em seguida, um WeatherFactory para dar a ele um comportamento climático específico do tipo pato.

radarbob
fonte