いい加減理解するデザインパターン-はじめに

3 min read読了の目安(約3200字

はじめまして

Zenn初記事です。よろしくお願いします。
仕事で設計についてを考える機会が増えてきました。その都度デザインパターンを調べるのですが、なんとなくわかった気になって(いわゆる「完全に理解した」)、いつも消化不良のままのうのうと生きてきました。いい加減理解するために一から勉強する過程を皆さんと共有していきたいと思い、始めた次第です。主に本でインプットしたものを自分の言葉で、ソースコードで書いていきます。
(私自身、見た目は大人、頭脳は子どもエンジニアなので、間違っていることがあればビジバシご指摘ください🙇‍♂️)

こんな人に読んでもらえたら

「デザインパターンって前々から聞くけど、正直よく分かっていない。。」
「なんか無駄にファイル数増えそうだし、小難しそうだし、複雑に感じるけど何が良いの?」
「プロジェクトの規模が大きくなってきて、いよいよその場しのぎの実装じゃ手に負えなくなってきた..」

参考本

本棚に長いこと埃がかぶっていたこの中古本を使います。

https://www.amazon.co.jp/Head-Firstデザインパターン-―頭とからだで覚えるデザインパターンの基本-Eric-Freeman/dp/4873112494/ref=pd_sbs_5?pd_rd_w=J4Zng&pf_rd_p=7997b82e-5553-4baa-ac55-976d37fe0def&pf_rd_r=8XZ33C6H0DRZ8FCKDV68&pd_rd_r=58456907-4a80-420b-abf0-36c97ccacd9f&pd_rd_wg=mDg7l&pd_rd_i=4873112494&psc=1

言語は

pythonを使います。

デザインパターンというけれど

そういう私自身もデザインパターンはどういうメリットがあるのかと、ずっとモヤモヤしています。
例えば、こういうソースコードがあったとします。

order.py
import pizza

def orderPizza(type):
    if type == "チーズ":
        pizza1 = pizza.CheesePizza()
    if type == "ギリシャ":
        pizza1 = pizza.GreekPizza()
    if type == "ペパロニ":
        pizza1 = pizza.PepperoniPizza()
    pizza1.prepare()
    pizza1.bake()
    pizza1.cut()
    pizza1.box()
    
    return pizza1

if __name__ == "__main__":
    orderPizza("チーズ")
    orderPizza("ギリシャ")
    orderPizza("ペパロニ")
pizza.py
class Pizza:
    def __init__(self):
        print("init")
        
    def prepare(self):
        print("準備")

    def bake(self):
        print("焼く")

    def cut(self):
        print("切る")

    def box(self):
        print("箱詰め")

    
class CheesePizza:
    def __init__(self):
        print("チーズinit")
        
    def prepare(self):
        print("準備")

    def bake(self):
        print("焼く")

    def cut(self):
        print("切る")

    def box(self):
        print("箱詰め")


class GreekPizza:
    def __init__(self):
        print("ギリシャinit")
        
    def prepare(self):
        print("準備")

    def bake(self):
        print("焼く")

    def cut(self):
        print("切る")

    def box(self):
        print("箱詰め")


class PepperoniPizza:
    def __init__(self):
        print("ペパロニinit")
        
    def prepare(self):
        print("準備")

    def bake(self):
        print("焼く")

    def cut(self):
        print("切る")

    def box(self):
        print("箱詰め")

これを見た時、「え?別に普通じゃね、何が悪いの?」と思った方、私も同じ感想を持ちました。
学生の時にCやオブジェクト指向を軽ーーく触れたことがある方、デザインパターンを全く知らない方からすれば、こういったソースコードを目にしても、無の感情で、何も気になさらないかも知れません。

「動けば、ええやん」そう誰しも最初は感じます。
しかし、ソフトウェアは一度リリースされた後は、もれなく保守が待っています。機能の追加・削除・変更があります。実装の担当者も変わります。納期もあるでしょうし、バグが出ようものならすぐに直せと上司に言われるかもしれません。そういった時、開発者は思うはずです。

「修正や変更箇所は可能な限り少なくあって欲しい...!」と。

その願いを一部叶えてくれるのが、デザインパターンなのだと思っています。
つまり、こういう変更(1ファイルが1000行を越えるようなソースコードの中から変更箇所を探す)のような、気の遠くなる作業を避けたい訳です。

じゃどうしたらいいのか

本を読みながら私も絶賛勉強中です。
今のところ、2つほど重要な事があると心得ました。

  • 変更が頻繁に起こるコードは、別のクラスに移した方が良い→カプセル化
  • 処理(ピザなら準備/焼く/切る/箱詰め)に共通点があれば、まとめた方が良い→インタフェース

しかし、これはオブジェクト指向のイロハであって、この2つを意識して実装したからといってデザインパターンのデの字も作れていません。

次回

Factoryパターンについて、自分なりに書いていきたいと思います。