Patrón de estrategia del refactor de Python para usar la clase base abstracta -- python campo con object-oriented campo con design-patterns campo con strategy-pattern camp codereview Relacionados El problema

refactor python strategy pattern to use abstract base class


3
vote

problema

Español

Me encontré con esta implementación de patrones de estrategia

https : //github.com/jtortorelli/head-first-design-patterns-python/blob/master/src/python/chapter_1/adventure_game.py

  rm.close()4  

¿Sería correcto refactarlo de la siguiente manera, utilizando un ABC?

  rm.close()5  
Original en ingles

I came across this strategy pattern implementation

https://github.com/jtortorelli/head-first-design-patterns-python/blob/master/src/python/chapter_1/adventure_game.py

class Character:     def __init__(self):         self.weapon_behavior = None      def set_weapon(self, weapon_behavior):         self.weapon_behavior = weapon_behavior      def fight(self):         self.weapon_behavior.use_weapon()   class Queen(Character):     def __init__(self):         super().__init__()         self.weapon_behavior = KnifeBehavior()   class King(Character):     def __init__(self):         super().__init__()         self.weapon_behavior = BowAndArrowBehavior()   class Troll(Character):     def __init__(self):         super().__init__()         self.weapon_behavior = AxeBehavior()   class Knight(Character):     def __init__(self):         super().__init__()         self.weapon_behavior = SwordBehavior()   class WeaponBehavior:     def use_weapon(self):         raise NotImplementedError   class KnifeBehavior(WeaponBehavior):     def use_weapon(self):         print("Stabby stab stab")   class BowAndArrowBehavior(WeaponBehavior):     def use_weapon(self):         print("Thwing!")   class AxeBehavior(WeaponBehavior):     def use_weapon(self):         print("Whack!")   class SwordBehavior(WeaponBehavior):     def use_weapon(self):         print("Thrust!")   knight = Knight() king = King() queen = Queen() troll = Troll() knight.fight() king.fight() queen.fight() troll.fight() 

Would it be correct to refactor it the following way, using an ABC?

from abc import ABC, abstractmethod   class Character:     def __init__(self):         self.weapon_behavior = None      def set_weapon(self, weapon_behavior):         self.weapon_behavior = weapon_behavior      def fight(self):         self.weapon_behavior.use_weapon()   class Queen(Character):     def __init__(self):         super().__init__()         self.weapon_behavior = KnifeBehavior()   class King(Character):     def __init__(self):         super().__init__()         self.weapon_behavior = BowAndArrowBehavior()   class Troll(Character):     def __init__(self):         super().__init__()         self.weapon_behavior = AxeBehavior()   class Knight(Character):     def __init__(self):         super().__init__()         self.weapon_behavior = SwordBehavior()   class WeaponBehavior(ABC):     @abstractmethod     def use_weapon(self, message):         print(message)  class KnifeBehavior(WeaponBehavior):      def use_weapon(self):         super().use_weapon("Stabby stab stab")   class BowAndArrowBehavior(WeaponBehavior):     def use_weapon(self):         super().use_weapon("Thwing!")  class AxeBehavior(WeaponBehavior):     def use_weapon(self):         super().use_weapon("Whack!")   class SwordBehavior(WeaponBehavior):     def use_weapon(self):         super().use_weapon("Thrust!")   knight = Knight() king = King() queen = Queen() troll = Troll() knight.fight() king.fight() queen.fight() troll.fight() 
           
         
         

Lista de respuestas

3
 
vote
vote
La mejor respuesta
 

Solo las clases de carácter y armas son realmente útiles y ninguno de los dos necesita heredar nada. El resto puede ser solo funciones de fábrica, porque solo los constructores difieren. Si un constructor de clase hace algo, excepto asignar argumentos a las propiedades, probablemente esté equivocado.

El patrón de estrategia se basa en la composición en lugar de la herencia.

  class Character:     def __init__(self, weapon):         self.weapon = weapon      def set_weapon(self, weapon):         self.weapon = weapon      def fight(self):         self.weapon.use()   def Queen():     return Character(Knife())  def King():     return Character(Bow())  class Weapon:     def __init__(self, message):        self.message = message     def use(self):        print(self.message)   def Knife():     return Weapon("Stabby stab stab")  def Bow():     return Weapon("Thwing!")   king = King() queen = Queen() king.fight() queen.fight() queen.set_weapon(Bow()) queen.fight()   

Aviso que he eliminado el behavior parte de los nombres, ya que parecía un poco inútil.

También he cambiado de nombre use_weapon() a solo use() porque se llama en una variable 9988777665544338 , y así parecía redundante.

Aviso, que a menos que utilice el método 9988776665544339 en una instancia de carácter construido (es decir, para cambiar de arma en medio de la batalla), la clase de carácter sería inútil, porque todo podría haberse hecho Con las armas solo. Por supuesto, sé que esto es solo un código de demostración de patrones, pero quería señalar de todos modos ...

Como bono, aquí hay algo (no solo) para el rey :) También note la composición de nuevo, se prefiere la composición sobre la herencia para proporcionar flexibilidad.

  __setattr__0  
 

Only the Character and WeaponBehaviour classes are actually useful and neither of them needs to inherit anything. The rest can be just factory functions, because only the constructors differ. If a class constructor does anything except assign arguments to properties, it is probably wrong.

Strategy pattern is based on composition rather then inheritance.

class Character:     def __init__(self, weapon):         self.weapon = weapon      def set_weapon(self, weapon):         self.weapon = weapon      def fight(self):         self.weapon.use()   def Queen():     return Character(Knife())  def King():     return Character(Bow())  class Weapon:     def __init__(self, message):        self.message = message     def use(self):        print(self.message)   def Knife():     return Weapon("Stabby stab stab")  def Bow():     return Weapon("Thwing!")   king = King() queen = Queen() king.fight() queen.fight() queen.set_weapon(Bow()) queen.fight() 

Notice that I have removed the behavior part of the names as it seemed a bit useless.

I have also renamed use_weapon() to just use() because it is called on a weapon variable, and so it seemed redundant.

Also notice, that unless I used the set_weapon() method on a constructed Character instance (ie. to switch weapon in middle of battle), the Character class would be useless, because everything could have been done with the weapons alone. Of course I know this is just a pattern demonstration code, but I wanted to point out anyway..

As a bonus, here is something (not only) for the king :) Also notice how again composition is prefered over inheritance to provide flexibility.

class DoubleWeapon:     def __init__(self, left, right):         self.left = left         self.right = right     def use(self):         self.left.use()         self.right.use()  king.set_weapon(DoubleWeapon(Knife(), Sword())) king.fight() ``` 
 
 

Relacionados problema

2  Implementar el patrón de estrategia para 1. Informe de impresión. 2. Tipo de película [CERRADO]  ( Implement strategy pattern for 1 print report 2 movie type ) 
cerrado . Esta pregunta necesita detalles o claridad . Actualmente no está aceptando respuestas. ...

3  Patrón de estrategia del refactor de Python para usar la clase base abstracta  ( Refactor python strategy pattern to use abstract base class ) 
Me encontré con esta implementación de patrones de estrategia https : //github.com/jtortorelli/head-first-design-patterns-python/blob/master/src/python/cha...

3  Calculadora de diseño orientado a objetos  ( Calculator object oriented design ) 
Estoy apuntando a implementar una calculadora de una manera orientada a objetos. Aquí está la solución utilizando el patrón de estrategia. Esperando algun...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos