รูปแบบกลยุทธ์ refactor python เพื่อใช้คลาสฐานนามธรรม
ฉันเจอรูปแบบการใช้กลยุทธ์นี้
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()
จะถูกต้องหรือไม่หากต้องการ refactor ด้วยวิธีต่อไปนี้โดยใช้ 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()
คำตอบ
เฉพาะคลาสตัวละครและอาวุธ Behaviour เท่านั้นที่มีประโยชน์และไม่จำเป็นต้องสืบทอดอะไรเลย ส่วนที่เหลืออาจเป็นเพียงฟังก์ชั่นของโรงงานเนื่องจากตัวสร้างเท่านั้นที่แตกต่างกัน ถ้าตัวสร้างคลาสทำอะไรก็ได้ยกเว้นกำหนดอาร์กิวเมนต์ให้กับคุณสมบัติก็อาจจะผิด
รูปแบบกลยุทธ์ขึ้นอยู่กับองค์ประกอบมากกว่าการถ่ายทอดทางพันธุกรรม
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()
สังเกตว่าฉันได้ลบbehaviorส่วนหนึ่งของชื่อออกไปแล้วเพราะดูเหมือนจะไร้ประโยชน์ไปหน่อย
ฉันยังเปลี่ยนชื่อเป็นuse_weapon()เพียงuse()เพราะเรียกใช้weaponตัวแปรดังนั้นมันจึงดูเหมือนซ้ำซ้อน
โปรดสังเกตด้วยว่าหากฉันไม่ใช้set_weapon()วิธีการในอินสแตนซ์ตัวละครที่สร้างขึ้น (เช่นการสลับอาวุธระหว่างการต่อสู้) คลาสตัวละครจะไร้ประโยชน์เพราะทุกอย่างสามารถทำได้ด้วยอาวุธเพียงอย่างเดียว แน่นอนฉันรู้ว่านี่เป็นเพียงรหัสสาธิตรูปแบบ แต่ฉันก็อยากจะชี้ให้เห็นอยู่ดี ..
เป็นโบนัสนี่คือบางสิ่งบางอย่าง (ไม่เพียง แต่) สำหรับกษัตริย์ :) โปรดสังเกตด้วยว่าการจัดองค์ประกอบนั้นเป็นอย่างไรมากกว่าการสืบทอดเพื่อให้มีความยืดหยุ่น
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()
```