ChatGPTはデザインパターンを用いたリファクタリングもできるのねという話。

 ふとChatGPTはリファクタリングができるらしいけど、デザインパターンを用いたリファクタリングもできるのかなあと思って衝動的に聞いてみました。
結果としてはガッツリできたので便利と思う反面脅威ですね。

リファクタリング前コード

 あくまで例なので単純ですが、とりあえず以下のようなよろしくないコードを書きました。

def get_foo(kind):
    if kind == "1":
        return "foo"
    elif kind == "2":
        return "ふー"
    elif kind == "3":
        return "フー"

def get_bar(kind):
    if kind == "1":
        return "bar"
    elif kind == "2":
        return "ばー"
    elif kind == "3":
        return "バー"

def get_hoge(kind):
    if kind == "1":
        return "hoge"
    elif kind == "2":
        return "ほげ"
    elif kind == "3":
        return "ホゲ"

kind = input("入力")
print(get_foo(kind) + get_bar(kind) + get_hoge(kind))

 inputで1~3を入力すると、foobarhoge・ふーばーほげ・フーバーホゲとそれぞれに表示を変えて表示されます。kindが0とか4とかだと誤作動起こすと思いますがまあそれは今回割愛で。
 同じ条件式が3つの関数内で登場するというCode Smellがするコードです。kindの種類が増えるとif文がそれぞれの関数で追加される変更に弱いコードです。これは各関数が近い位置にあるので良いですが、関数の位置がとっ散らかってたらget_hogeとget_barにはif文追加したけどget_fooには追加し忘れてバグになるとかめっちゃ起こりそうなコードですね。

ChatGPTに訪ねた文言

 kindの状態によるのでStateパターンを用いればこのif文を消すことができますね。というわけで以下のようにChatGPTに訪ねました。

以下のPythonコードをStateパターンを用いてリファクタリングしてください

(以下コード。無駄に行数食うので省略)

ChatGPTの答え

そして返ってきたのがこちら。

class State:
    def get_foo(self):
        pass

    def get_bar(self):
        pass

    def get_hoge(self):
        pass

class Kind1State(State):
    def get_foo(self):
        return "foo"

    def get_bar(self):
        return "bar"

    def get_hoge(self):
        return "hoge"

class Kind2State(State):
    def get_foo(self):
        return "ふー"

    def get_bar(self):
        return "ばー"

    def get_hoge(self):
        return "ほげ"

class Kind3State(State):
    def get_foo(self):
        return "フー"

    def get_bar(self):
        return "バー"

    def get_hoge(self):
        return "ホゲ"

class KindContext:
    def __init__(self, kind):
        if kind == "1":
            self.state = Kind1State()
        elif kind == "2":
            self.state = Kind2State()
        elif kind == "3":
            self.state = Kind3State()

    def get_foo(self):
        return self.state.get_foo()

    def get_bar(self):
        return self.state.get_bar()

    def get_hoge(self):
        return self.state.get_hoge()

kind = input("入力")
context = KindContext(kind)
print(context.get_foo() + context.get_bar() + context.get_hoge())

 いやー素晴らしい。忌々しいif文を1つにすることがちゃんとできてます。あとはクラス名を変更すればOKですね。

不明点

  1. 今回はかなりわかり易い例。実践的なコードでここまでできるだろうか?
  2. 尋ねる文言にStateパターンを指定した。つまりこのケースではStateパターンを使用したほうが良いと人間が判断した。指定しなくてもやってくれるだろうか?ちなみに「もう一回尋ねたら?」と思うかも知れませんが、もうすでにこの例を出力しているのでStateパターンの文言を抜いても同じ答えが返ってくるでしょう。

 特に2については気になります。人間がデザインパターンを理解している必要があるかどうかが問われます。必要ないならデザインパターンを勉強する必要も無くなっちゃうかも。