週末!プログラミング部

ソフトウェア開発ネタを中心に自分でいろいろ調べた内容を自分の勝手な解釈で思うがままに書いくためのブログ。サンプルソースコード、API、プラットフォーム、プログラミング言語、開発環境などを調査、分析して追求いく予定です。

Pythonでデザインパターン 拾ノ型「Strategy」

今回はPythonの勉強しながらデザインパターンのStrategyをやってみました。
他のパターンにつきましては、以下の目次記事をご参照ください。

Strategyとは

直訳すると「戦略」ですね。
wikiには「アルゴリズムを使用者から独立したまま様々に変化させることができるようになる」とあります。

このパターンはBridgeパターンとよく似ていますが、 Bridgeパターンは機能拡張を目的としているのに対して、Strategyパターンは機能切り替えを目的にしている?と勝手に認識しています笑
いずれにしてもjavaC#など、インタフェースがある言語ではあまり使わないパターンかな(;^ω^)

Strategyについて考えてみる

Bridgeパターンと同様の例ですが、以下のようなインタフェースがあったとします。

from abc import ABCMeta, abstractmethod

class Hoge(metaclass=ABCMeta) :
    @abstractmethod
    def functionA(self) :
        pass

このインタフェースを実装したクラスは以下のような感じでしょうか?

class Foo(Hoge)
    def functionA(self) :
        print("Foo機能")

class Bar(Hoge)
    def functionA(self) :
        print("Bar機能")

そしてこのクラスを使用するとすればこのような感じですかね?

if __name__ == "__main__" :
    foo = Foo()
    bar = Bar()

    foo.functionA()
    bar.functionA()

これでもいいのですが、Strategyパターンですと以下のようなStrategyクラスを作成します。

class Strategy(Hoge)
    def __init__(self, hoge: Hoge):
        self.setHogeHoge(hoge)

    def setHogeHoge(self, hoge) :
        self._hoge = hoge

    def functionA(self) :
        self._hoge.functionA()

そしてStrategyクラスにインスタンを設定することで機能切り替えが行えるようになります!

if __name__ == "__main__" :
    
    obj = Strategy(Foo())
    obj.functionA() # Foo機能

    obj.setHogeHoge(Bar())
    obj.functionA() # Bar機能

サンプルコード

Bridgeパターンと同様にポケモンでピカピカ言ってるアイツを倒します。(๑◕ܫ◕๑)
BridgeパターンではSkillクラスを拡張するクラスを使ってダメージを与えていました。
今回は、"効果抜群クラス"と"効果は今ひとつクラス"を"効果クラス"で切り替えられるようにしています。
微妙な違いでわかりにくいかもですがお許しください(´ε`;)

# coding: utf-8

from abc import ABCMeta, abstractmethod

# 技クラス
class Skill(metaclass=ABCMeta) :
    def __init__(self, name : str, type : str) :
        self.__name = name
        self.__type = type
    
    def getName(self) -> str:
        return self.__name
    
    def getType(self) -> str:
        return self.__type
    
    @abstractmethod
    def getDamege(self) :
        pass

# 効果クラス
class EffectiveInterface(metaclass=ABCMeta) :
    @abstractmethod
    def getDamege(self, skill : Skill) :
        pass

# Strategyパターン
class Effective(EffectiveInterface) :
    def __init__(self, effect):
        self.setEffect(effect)

    def setEffect(self, effect) :
        self._effect = effect

    def getDamege(self, skill : Skill) :
        return self._effect.getDamege(skill)
        
# 効果抜群クラス
class superEffective(EffectiveInterface):
    def getDamege(self, skill : Skill):
        print("効果抜群だ!!")
        return skill.getDamege() * 1.5

# 効果は今ひとつクラス
class notVeryEffective(EffectiveInterface):
    def getDamege(self, skill : Skill):
        print("効果は今ひとつのようだ...")
        return skill.getDamege() * 0.75

# 技:地震
class earthquake(Skill):
    def __init__(self):
        super().__init__("じしん", "じめん")

    def getDamege(self):
        return 100

# 技:たいあたり
class taiatari(Skill):
    def __init__(self):
        super().__init__("たいあたり", "ノーマル")

    def getDamege(self):
        return 20

# 技:かぜおこし
class gust(Skill):
    def __init__(self):
        super().__init__("かぜおこし", "ひこう")

    def getDamege(self):
        return 40


class Pikachu(object):
    def __init__(self, name, hp):
        self.__name = name
        self.__hp = hp

    def Damege(self, skill):
        if skill.getType() == 'じめん':
            damege = Effective(superEffective()).getDamege(skill)

        elif skill.getType() == 'ひこう':
            damege = Effective(notVeryEffective()).getDamege(skill)

        else:
            damege = skill.getDamege()

        self.__hp = self.__hp - damege
        
        if self.__hp <= 0 :
            print(self.__name, "は たおれた")
            print("め の まえ が まっしろ に なった")

if __name__ == "__main__" :
    
    skill_taiatari = taiatari()
    skill_gust = gust()
    skill_earthquake = earthquake()
    
    pikachu = Pikachu(name = "ピカチュウ", hp = 75)
    
    # たいあたりしてみる
    print("------------")
    print(skill_taiatari.getName(), "を つかった")
    pikachu.Damege(skill_taiatari)
    
    # かぜおこしを使ってみる
    print("------------")
    print(skill_gust.getName(), "を つかった")
    pikachu.Damege(skill_gust)
    
    # じしんを使ってみる
    print("------------")
    print(skill_earthquake.getName(), "を つかった")
    pikachu.Damege(skill_earthquake)

結果はこんな感じです。
今回も上手に倒せましたか???

$ python Strategy.py
------------
たいあたり を つかった
------------
かぜおこし を つかった
効果は今ひとつのようだ...
------------
じしん を つかった
効果抜群だ!!
ピカチュウ は たおれた
め の まえ が まっしろ に なった