รูปแบบกลยุทธ์ refactor python เพื่อใช้คลาสฐานนามธรรม

Oct 07 2020

ฉันเจอรูปแบบการใช้กลยุทธ์นี้

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()

คำตอบ

3 slepic Oct 07 2020 at 23:31

เฉพาะคลาสตัวละครและอาวุธ 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()
```