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