作成日: 2023/04/22
0

Python3でよく使うデザインパターン

はじめに

ソフトウェア開発において、デザインパターンは良い設計を行う上で重要な考え方のひとつです。デザインパターンとは、複雑な問題を解決するための再利用可能なソリューションを提供する汎用的なアプローチのことです。Pythonには、多くのデザインパターンがあります。この記事では、Python3でよく使うデザインパターンについて紹介します。

1. Singleton Pattern

Singletonパターンは、アプリケーション内で唯一のインスタンスを作成し、それをグローバルに利用するための設計パターンです。Pythonには、複数のスレッドからシングルトンオブジェクトにアクセスする場合に問題が発生する可能性があります。PythonのスレッドモデルはGIL(Global Interpreter Lock)を持っているため、同時にアクセスできるのは1つのスレッドのみです。

以下のコードは、Singletonパターンを実装した例です。

class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance

2. Factory Pattern

Factoryパターンは、オブジェクトの生成を担当するクラスを用意し、クライアントからの要求に基づいてオブジェクトを生成する設計パターンです。

以下のコードは、Factoryパターンを実装した例です。

class Car(object):
    def __init__(self, name):
        self.name = name

    def drive(self):
        print("Driving", self.name)

class CarFactory(object):
    def create_car(self, name):
        return Car(name)

if __name__ == '__main__':
    car_factory = CarFactory()
    car1 = car_factory.create_car("Toyota")
    car2 = car_factory.create_car("Honda")
    car1.drive() # Driving Toyota
    car2.drive() # Driving Honda

3. Observer Pattern

Observerパターンは、オブジェクトの状態変化を他のオブジェクトに通知するための設計パターンです。オブジェクト間の依存度を下げ、耦合度を減らすことができます。Pythonは、Observableパッケージを提供しており、これを利用することで簡単にObserverパターンを実装することができます。

以下のコードは、Observableパッケージを利用してObserverパターンを実装した例です。

from observable import Observable

class Article(Observable):
    def __init__(self):
        Observable.__init__(self)
        self.content = ""

    def set_content(self, content):
        self.content = content
        self.notify_observers()

class Reader():
    def __init__(self, name):
        self.name = name

    def update(self, observable, *args, **kwargs):
        print(self.name, "is reading a new article:", observable.content)

if __name__ == '__main__':
    a = Article()
    r1 = Reader("Steve")
    r2 = Reader("James")
    a.add_observer(r1)
    a.add_observer(r2)
    a.set_content("New Article") # Steve is reading a new article: New Article, James is reading a new article: New Article

4. Decorator Pattern

Decoratorパターンは、オブジェクトに新しい機能を追加するために既存の機能をラップする設計パターンです。ラッピングにより、機能の追加が容易になります。

以下のコードは、Decoratorパターンを実装した例です。

class Component(object):
    def __init__(self):
        pass

    def operation(self):
        pass

class ConcreteComponent(Component):
    def __init__(self):
        Component.__init__(self)

    def operation(self):
        print("ConcreteComponent operation")

class Decorator(Component):
    def __init__(self, component):
        Component.__init__(self)
        self._component = component

    def operation(self):
        self._component.operation()

class ConcreteDecorator(Decorator):
    def __init__(self, component):
        Decorator.__init__(self, component)

    def operation(self):
        Decorator.operation(self)
        self.added_behavior()

    def added_behavior(self):
        print("Added Behavior")

if __name__ == '__main__':
    c = ConcreteComponent()
    d = ConcreteDecorator(c)
    d.operation() # ConcreteComponent operation Added Behavior

5. Adapter Pattern

Adapterパターンは、既存のクラスを別のインタフェースに適合させる設計パターンです。このパターンを使用することで、既存のクラスを改修することなく新機能を追加することができます。

以下のコードは、Adapterパターンを実装した例です。

class Target(object):
    def request(self):
        print("Target request")

class Adaptee(object):
    def specific_request(self):
        print("Adaptee specific_request")

class Adapter(Target):
    def __init__(self):
        Target.__init__(self)
        self._adaptee = Adaptee()

    def request(self):
        self._adaptee.specific_request()

if __name__ == '__main__':
    t = Target()
    t.request() # Target request
    a = Adapter()
    a.request() # Adaptee specific_request

6. Template Method Pattern

Template Methodパターンは、アルゴリズムの骨格を定義し、具象クラスでアルゴリズムの一部をカスタマイズする設計パターンです。

以下のコードは、Template Methodパターンを実装した例です。

class AbstractClass(object):
    def template_method(self):
        self.operation1()
        self.required_operation1()
        self.operation2()
        self.hook()

    def operation1(self):
        print("AbstractClass operation1")

    def operation2(self):
        print("AbstractClass operation2")

    def hook(self):
        pass

    def required_operation1(self):
        pass

class ConcreteClass(AbstractClass):
    def required_operation1(self):
        print("ConcreteClass operation1")

    def hook(self):
        print("ConcreteClass hook")

if __name__ == '__main__':
    c = ConcreteClass()
    c.template_method() # AbstractClass operation1 ConcreteClass operation1 AbstractClass operation2 ConcreteClass hook

まとめ

Python3でよく使うデザインパターンについて紹介しました。デザインパターンを用いることで、柔軟にコードを変更できるアプリケーションを開発することができます。デザインパターンは、関数型プログラミングにも利用可能です。デザインパターンの詳細については、以下のリンクを参照してください。


フルスタックエンジニア。徒然なるままに記事を投稿していきます。日々学習。