はじめに
この記事は個人的な勉強メモです。inputしたものはoutputしなくてはという強迫観念に駆られて記事を書いています。
あわよくば詳しい人に誤りの指摘やアドバイスを頂ければいいなという思いを込めてQiitaの記事にしています。
エンジニアとして社会人生活を送っていますが、デザインパターンについてちゃんと学んだことがなかったので勉強してみました。
ここに記載している内容は
https://github.com/ck-fm0211/notes_desigh_pattern
にuploadしています。
過去ログ
TemplateMethodパターン
- スーパークラスで処理の枠組みを定め、サブクラスでその具体的内容を実装する
実際に使ってみる
題材
- ざっくりした業務マニュアルを作成する
# -*- coding:utf-8 -*-
from abc import ABCMeta, abstractmethod
class Manual(metaclass=ABCMeta):
@abstractmethod
def check_mail(self):
pass
@abstractmethod
def edit_list(self):
pass
@abstractmethod
def send_mail(self):
pass
class JohnManual(Manual):
def check_mail(self):
print("mailアプリでメール確認")
def edit_list(self):
print("VBAを使ってリスト修正")
def send_mail(self):
print("VBAからそのままメール送信")
- テンプレートとなる
Manual
クラスを作成 - Johnはそれを継承した
JohnManual
を作成 - テンプレートの流れに沿って独自のやり方を実現
TemplateMethodパターンのまとめ
FactoryMethodパターン
- オブジェクトの生成方法に一工夫加えることで、より柔軟にオブジェクトを生成することを目的とするもの
- インスタンスの生成をサブクラスに行わせることで、より柔軟に生成するインスタンスを選択することが可能となる
- 通常、以下のようにインスタンスを生成する
chair_person = Mary()
- FactoryMethodパターンではオブジェクトの生成を担うメソッド(factory method)を通して間接的にオブジェクトを生成する
class Factory(metaclass=ABCMeta):
@abstractmethod
def _create_product(self, owner):
pass
def create(self, owner):
self.__p = self._create_product(owner)
実際に使ってみる
題材
- メモをとるという業務を定義
- メモを取る先の材料(紙、電子ペーパー)は個人の自由
- Johnは電子ペーパーにメモを取りたい
# -*- coding:utf-8 -*-
from abc import ABCMeta, abstractmethod
class Editable:
pass
class Paper(Editable):
pass
class Manual(metaclass=ABCMeta):
@abstractmethod
def edit(self, material: Editable):
pass
@abstractmethod
def create_material(self):
return Paper()
@abstractmethod
def take_memo(self):
material = self.create_material()
self.edit(material)
class ElectronicPaper(Editable):
pass
class JohnManual(Manual):
def edit(self, material):
print("電子ペーパーにメモをとる")
def create_material(self):
return ElectronicPaper()
def take_memo(self):
material = self.create_material()
self.edit(material)
- インスタンス生成のためのメソッドを用意する。そして、そのインスタンスを生成するためのメソッドを通してインスタンスの生成を行う。
- create_material メソッドをオーバーライドするメソッドを記述し、メモをとる先の材料を自由に選択することができるようになる
FactoryMethodパターンのまとめ
Singletonパターン
- singleton とは一枚札のこと。一枚札とはトランプの一組に唯一のカード。Singleton パターンとは、このような唯一の存在を保証するためのパターン。
- あるクラスのインスタンスが一つしかないことを保証したい場合につかう
実際に使ってみる
題材
- 図書館の貸出帳を考える
- 図書の貸出に当たって、その貸出帳がいくつあるのかわからないような状態では、管理がとても難しくなる
# -*- coding:utf-8 -*-
class RegisterNote:
__singleton = None
__register = None
def __new__(cls, *args, **kwargs):
if cls.__singleton == None:
cls.__singleton = super(RegisterNote, cls).__new__(cls)
return cls.__singleton
def set_register(self, register=None):
self.__register = register
def get_register(self):
return self.__register
RegisterNote() # クラス定義の直下に書いて、インスタンスを作るために必ず呼ぶ
- 下記の通り、2つのインスタンス(
rn1
rn2
)は同じインスタンスだということがわかる
>>> class RegisterNote:
... __singleton = None
... __register = None
...
... def __new__(cls, *args, **kwargs):
... if cls.__singleton == None:
... cls.__singleton = super(RegisterNote, cls).__new__(cls)
... return cls.__singleton
...
... def set_register(self, register=None):
... self.__register = register
...
... def get_register(self):
... return self.__register
...
>>> RegisterNote()
<RegisterNote object at 0x10c48f9e8>
>>> rn1 = RegisterNote()
...
>>> rn2 =RegisterNote()
...
>>> rn1
<RegisterNote object at 0x10c48f9e8>
>>> rn2
<RegisterNote object at 0x10c48f9e8>
>>> rn2.set_register('book book book')
>>> rn1.get_register()
'book book book'
備考
- Javaの場合はprivateを使えば容易にsingletonを実装できる
public class RegisterNote{
private static RegisterNote registerNote = new RegisterNote();
private RegisterNote(){}
public static RegisterNote getInstance(){
return registerNote;
}
}
- registerNote は、RegisterNote クラスが初期化されるときに生成される。
- クラスが初期化されるタイミングは Java の言語仕様で定義されており、 初めてインスタンス化された時や、初めて static メソッドが呼び出されたタイミングなどに行われる。
- すなわち、このサンプルプログラムでは、staticメソッドであるgetInstance メソッドが初めて呼ばれるときにRegisterNode クラスが初期化され、そのときに一度だけRegisterNode クラスのインスタンスが生成されることになる。
- この後、getInstance メソッドが呼ばれたときには、既に生成されている registerNote オブジェクトが返されることになる。
- pythonにはprivateが存在しないので、上記のように
__new__()
メソッドを使う。-
__init__()
メソッドより前に呼ばれ、インスタンスを生成して返す
-
Singletonパターンのまとめ
参考