目次
● Chain of Responsibility パターン
● Command パターン
● Interpreter パターン
● Iterator パターン
● Mediator パターン
● Memento パターン
● Observer パターン
● State パターン
● Strategy パターン
● Template Method パターン
● Visitor パターン
その他のデザインパターン
● Chain of Responsibility パターン
ChainOfResponsibility.py
# ----------------------------------------------------------------------
# Chain of Responsibility パターン
# ----------------------------------------------------------------------
# 処理の責任をたらい回しにします。
from abc import ABCMeta, abstractmethod
class Handler(metaclass=ABCMeta):
def __init__(self, next_handler=None):
self.next_handler = next_handler
@abstractmethod
def handle(self, day):
pass
class Handler01(Handler):
def handle(self, day):
if day <= 2:
print('{}日の休暇を承認した。承認者:Handler01'.format(str(day)))
else:
self.next_handler.handle(day)
class Handler02(Handler):
def handle(self, day):
if 2 < day <= 5:
print('{}日の休暇を承認した。承認者:Handler02'.format(str(day)))
else:
self.next_handler.handle(day)
class FinalHandler99(Handler):
def handle(self, day):
if 5 < day <= 10:
print('{}日の休暇を承認した。承認者:FinalHandler99'.format(str(day)))
else:
print('11日以上の休暇を承認できない。承認者:FinalHandler99'.format(str(day)))
class Client:
def __init__(self):
h99 = FinalHandler99()
h02 = Handler02(h99)
self.handler = Handler01(h02)
def get_handler(self):
return self.handler
if __name__ == '__main__':
h = Client().get_handler()
for day in [2, 9, 3]:
h.handle(day)
実行結果:
2日の休暇を承認した。承認者:Handler01
9日の休暇を承認した。承認者:FinalHandler99
3日の休暇を承認した。承認者:Handler02
● Command パターン
Command.py
# ----------------------------------------------------------------------
# Command パターン
# ----------------------------------------------------------------------
# コマンドをクラスで表現します。
from abc import ABCMeta, abstractmethod
# 抽象コマンドクラス
class Command(metaclass=ABCMeta):
def __init__(self, receiver):
self.receiver = receiver
@abstractmethod
def execute(self):
pass
# 具象コマンドクラス
class StartCommand(Command):
def execute(self):
self.receiver.start()
# 具象コマンドクラス
class StopCommand(Command):
def execute(self):
self.receiver.stop()
# 具体的なアクションを定義するクラス
class Receiver:
def start(self):
print('処理内容: スタートアクション')
def stop(self):
print('処理内容: ストップアクション')
# コマンドを受け入れ、コマンドを実行するクラス
class Invoker:
def __init__(self):
self.commands = []
def add_command(self, command):
self.commands.append(command)
def remove_command(self, command):
self.commands.remove(command)
def run_command(self):
for cmd in self.commands:
cmd.execute()
if __name__ == '__main__':
receiver = Receiver()
start_cmd = StartCommand(receiver)
stop_cmd = StopCommand(receiver)
inv = Invoker()
inv.add_command(start_cmd)
inv.add_command(stop_cmd)
inv.run_command()
実行結果:
処理内容: スタートアクション
処理内容: ストップアクション
● Interpreter パターン
Interpreter.py
# ----------------------------------------------------------------------
# Interpreter パターン
# ----------------------------------------------------------------------
# 構文を解析し、規則をクラスで表現します。
from abc import ABCMeta, abstractmethod
class Expression(metaclass=ABCMeta):
@abstractmethod
def interpret(self, context=None): # contextは未使用
pass
class ValueExpression(Expression):
def __init__(self, value):
self.value = value
def interpret(self, context=None):
return self.value
class OperatorExpression(Expression):
def __init__(self, left, right):
self.left = left
self.right = right
def interpret(self, context=None):
pass
# 加算
class PlusExpression(OperatorExpression):
def __init__(self, left, right):
self.node = OperatorExpression(left, right)
def interpret(self, context=None):
return self.node.left.interpret() + self.node.right.interpret()
# 引き算
class SubExpression(OperatorExpression):
def __init__(self, left, right):
self.node = OperatorExpression(left, right)
def interpret(self, context=None):
return self.node.left.interpret() - self.node.right.interpret()
# 乗算
class MulExpression(OperatorExpression):
def __init__(self, left, right):
self.node = OperatorExpression(left, right)
def interpret(self, context=None):
return self.node.left.interpret() * self.node.right.interpret()
# 除算
class DivExpression(OperatorExpression):
def __init__(self, left, right):
self.node = OperatorExpression(left, right)
def interpret(self, context=None):
return self.node.left.interpret() / self.node.right.interpret()
# 中置記法(数式)を後置記法に変換するクラス
class Postfix:
def is_numeric(self, s):
try:
float(s)
except ValueError:
return False
else:
return True
# 後置記法の配列を取得
def get_postfix(self, expr):
operator_dict = {"*": 30, "/": 30, "+": 20, "-": 20, "(": 10, ")": 10}
stack = []
postfix_list = []
infix_expr = expr.replace(' ', '')
token_list = []
temstr = ''
for i in range(len(infix_expr)):
char = infix_expr[i]
is_operator = char in operator_dict.keys()
if char == '-':
if i == 0:
is_operator = False
else:
if infix_expr[i - 1] == '(':
is_operator = False
if is_operator:
if len(temstr) != 0:
token_list.append(temstr)
temstr = ''
token_list.append(char)
else:
temstr = temstr + char
if len(temstr) != 0:
token_list.append(temstr)
for token in token_list:
if self.is_numeric(token):
postfix_list.append(token)
elif token == "(":
stack.append(token)
elif token == ")":
top_token = stack.pop()
while top_token != "(":
postfix_list.append(top_token)
top_token = stack.pop()
else:
while len(stack) != 0 and operator_dict[stack[-1]] >= operator_dict[token]:
postfix_list.append(stack.pop())
stack.append(token)
while len(stack) != 0:
postfix_list.append(stack.pop())
return postfix_list
class Calculator:
def __init__(self):
self.root_expression = None
self.cal_success = True
self.postfix_list = []
# 二分木を構築
def get_binary_tree(self, exp):
p = Postfix()
self.postfix_list = p.get_postfix(exp) # 後置記法の配列
f = lambda x: float(x) if p.is_numeric(x) else x
post_list = list(map(f, self.postfix_list))
# 二分木を構築
expression_stack = []
operators = '+-*/'
for postfix in post_list:
item = str(postfix)
if item in operators:
right = expression_stack[-1]
left = expression_stack[-2]
expression_stack = expression_stack[0:-2]
if item == '+':
expression_stack.append(PlusExpression(left, right))
elif item == '-':
expression_stack.append(SubExpression(left, right))
elif item == '*':
expression_stack.append(MulExpression(left, right))
elif item == '/':
expression_stack.append(DivExpression(left, right))
else:
expression_stack.append(ValueExpression(postfix))
return expression_stack[0]
def get_expression_value(self, expression):
self.cal_success = True
rtn = 0
try:
self.root_expression = self.get_binary_tree(expression)
rtn = self.root_expression.interpret()
except Exception as e:
self.cal_success = False
print('不正な数式:[{}] (error:{})'.format(expression, e))
return rtn
if __name__ == '__main__':
# ----- Client -----
exp_list = []
exp_list.append('((3+5)/(10-8))*(2+3)')
exp_list.append('5*(-12.5 - 3)')
exp_list.append('-2*2 - (-9)')
cal = Calculator()
for exp in exp_list:
val = cal.get_expression_value(exp)
if cal.cal_success:
print('後置記法の数式:[{}]'.format(' '.join(cal.postfix_list)))
print('{} = {}'.format(exp, val))
実行結果:
後置記法の数式:[3 5 + 10 8 - / 2 3 + *]
((3+5)/(10-8))*(2+3) = 20.0
後置記法の数式:[5 -12.5 3 - *]
5*(-12.5 - 3) = -77.5
後置記法の数式:[-2 2 * -9 -]
-2*2 - (-9) = 5.0
● Iterator パターン
Iterator.py
# ----------------------------------------------------------------------
# Iterator パターン
# ----------------------------------------------------------------------
# 集合の各要素に順次にアクセスする方法を提供します。
from abc import ABCMeta, abstractmethod
class Iterator(metaclass=ABCMeta):
@abstractmethod
def has_next(self):
pass
@abstractmethod
def next(self):
pass
class Student:
def __init__(self, name):
self.name = name
def show_info(self):
print(self.name)
class StudentIterator(Iterator):
def __init__(self, students):
# 学生名を基準に降順でソート
self.students = sorted(students, key=lambda x: x.name, reverse=True)
self.index = 0
def has_next(self):
if self.students is None:
return False
return self.index < len(self.students)
def next(self):
stu = self.students[self.index]
self.index += 1
return stu
if __name__ == '__main__':
students = [Student('学生A'), Student('学生C'), Student('学生B')]
student_iterator = StudentIterator(students)
while student_iterator.has_next():
student = student_iterator.next()
student.show_info()
実行結果:
学生C
学生B
学生A
● Mediator パターン
Mediator.py
# ----------------------------------------------------------------------
# Mediator パターン
# ----------------------------------------------------------------------
# オブジェクト間の関係を中間オブジェクトで制御します。
from abc import ABCMeta, abstractmethod
class Mediator(metaclass=ABCMeta):
@abstractmethod
def send(self, message, colleague):
pass
class Colleague(metaclass=ABCMeta):
def __init__(self, mediator):
self.mediator = mediator
@abstractmethod
def send(self, message):
pass
@abstractmethod
def notify(self, message):
pass
class ConcreteColleagueA(Colleague):
def send(self, message):
self.mediator.send(message, self)
def notify(self, message):
print('同僚Aが入手した情報:{}'.format(message))
class ConcreteColleagueB(Colleague):
def send(self, message):
self.mediator.send(message, self)
def notify(self, message):
print('同僚Bが入手した情報:{}'.format(message))
class ConcreteMediator(Mediator):
def __init__(self):
self.__colleagueA = None
self.__colleagueB = None
@property
def colleagueA(self):
return
@colleagueA.setter
def colleagueA(self, value):
self.__colleagueA = value
@property
def colleagueB(self):
return
@colleagueB.setter
def colleagueB(self, value):
self.__colleagueB = value
def send(self, message, colleague):
if colleague == self.__colleagueA:
self.__colleagueB.notify(message)
else:
self.__colleagueA.notify(message)
if __name__ == "__main__":
m = ConcreteMediator()
a = ConcreteColleagueA(m)
b = ConcreteColleagueB(m)
m.colleagueA = a
m.colleagueB = b
a.send('運動が好きです。')
b.send('音楽が好きです。')
実行結果:
同僚Bが入手した情報:運動が好きです。
同僚Aが入手した情報:音楽が好きです。
● Memento パターン
Memento.py
# ----------------------------------------------------------------------
# Memento パターン
# ----------------------------------------------------------------------
# ある時点のオブジェクトの状態を保存し、オブジェクトを復元できるようにします。
class Originator:
def __init__(self, state, val):
self.state = state
self.val = val
def save_memento(self):
return Memento(self.state, self.val)
def recover_memento(self, memento):
self.state = memento.state
self.val = memento.val
def show_infor(self):
print('state: {} val: {}'.format(self.state, self.val))
class Memento:
def __init__(self, state, val):
self.state = state
self.val = val
class Caretaker:
def __init__(self, memento):
self.memento = memento
if __name__ == '__main__':
originator = Originator('状態1', 10)
originator.show_infor()
memento_temp = originator.save_memento()
caretaker = Caretaker(memento_temp)
originator.state = '状態2'
originator.val = 60
originator.show_infor()
originator.recover_memento(caretaker.memento)
originator.show_infor()
実行結果:
state: 状態1 val: 10
state: 状態2 val: 60
state: 状態1 val: 10
● Observer パターン
Observer.py
# ----------------------------------------------------------------------
# Observer パターン
# ----------------------------------------------------------------------
# 状態の変化を複数のオブジェクトに通知します。
from abc import ABCMeta, abstractmethod
# 抽象観察者
class Observer(metaclass=ABCMeta):
@abstractmethod
def update(self, notice):
pass
# 発信者(基底)
class Notice:
def __init__(self):
self.observers = []
def attach(self, obs):
if obs not in self.observers:
self.observers.append(obs)
def detach(self, obs):
try:
self.observers.remove(obs)
except ValueError:
pass
def notify(self):
for obs in self.observers:
obs.update(self)
# 観察者
class StudentObserver(Observer):
def __init__(self, name):
self.name = name
self.status = ''
self.notice = None
def register(self, notice):
self.notice = notice
notice.attach(self)
def unregister(self):
if self.notice:
self.notice.detach(self)
self.notice = None
def update(self, notice):
self.status = notice.status
def show_status(self):
print('{}:{}'.format(self.name, self.status))
# 発信者
class NoticeCenter(Notice):
def __init__(self):
super().__init__()
self.__status = ''
@property
def status(self):
return self.__status
@status.setter
def status(self, status):
self.__status = status
self.notify()
if __name__ == '__main__':
notice_center = NoticeCenter()
stu1 = StudentObserver('学生A')
stu1.register(notice_center)
stu2 = StudentObserver('学生B')
stu2.register(notice_center)
notice_center.status = '休憩開始'
stu1.show_status()
stu2.show_status()
notice_center.status = '休憩終了'
stu1.show_status()
stu2.show_status()
実行結果:
学生A:休憩開始
学生B:休憩開始
学生A:休憩終了
学生B:休憩終了
● State パターン
State.py
# ----------------------------------------------------------------------
# State パターン
# ----------------------------------------------------------------------
# 状態をクラスとして表現します。(クラスを切り替えることで「状態の変化」を表します)
from abc import ABCMeta, abstractmethod
# 抽象状態
class State(metaclass=ABCMeta):
@abstractmethod
def heat(self):
pass
@abstractmethod
def cool(self):
pass
# 液体状態を表すクラス
class Water(State):
def heat(self):
return Vapour()
def cool(self):
return Ice()
def __str__(self):
return '液体状態の水'
# 気体状態を表すクラス
class Vapour(State):
def heat(self):
return self
def cool(self):
return Water()
def __str__(self):
return '気体状態の水'
# 個体状態を表すクラス
class Ice(State):
def heat(self):
return Water()
def cool(self):
return self
def __str__(self):
return '個体状態の水'
class Context:
def __init__(self, state):
self.state = state
def heat(self):
self.state = self.state.heat()
def cool(self):
self.state = self.state.cool()
def set_state(self, state):
self.state = state
if __name__ == '__main__':
context = Context(Ice()) # 初期:個体状態
for i in range(0, 2):
pre_state = format(context.state)
context.heat()
print('{} → 加熱後 → {}'.format(pre_state, context.state))
print('-' * 35)
for i in range(0, 3):
pre_state = format(context.state)
context.cool()
print('{} → 冷却後 → {}'.format(pre_state, context.state))
実行結果:
個体状態の水 → 加熱後 → 液体状態の水
液体状態の水 → 加熱後 → 気体状態の水
-----------------------------------
気体状態の水 → 冷却後 → 液体状態の水
液体状態の水 → 冷却後 → 個体状態の水
個体状態の水 → 冷却後 → 個体状態の水
● Strategy パターン
Strategy.py
# ----------------------------------------------------------------------
# Strategy パターン
# ----------------------------------------------------------------------
# 各種のアルゴリズムを定義し、相互に置き換えられるようにします。
from abc import ABCMeta, abstractmethod
class Strategy(metaclass=ABCMeta):
@abstractmethod
def run(self):
pass
class StrategyAlgorithm1(Strategy):
def run(self):
print('アルゴリズム1での処理')
class StrategyAlgorithm2(Strategy):
def run(self):
print('アルゴリズム2での処理')
class Context:
def __init__(self, strategy):
self.strategy = strategy
def set_strategy(self, strategy):
self.strategy = strategy
def do_strategy(self):
self.strategy.run()
if __name__ == '__main__':
c = Context(StrategyAlgorithm1())
c.do_strategy()
c.set_strategy(StrategyAlgorithm2())
c.do_strategy()
実行結果:
アルゴリズム1での処理
アルゴリズム2での処理
● Template Method パターン
TemplateMethod.py
# ----------------------------------------------------------------------
# Template Method パターン
# ----------------------------------------------------------------------
# 抽象クラスで処理の枠組みを定め、サブクラスでその具体的な内容を実装します。
from abc import ABCMeta, abstractmethod
class Template(metaclass=ABCMeta):
@abstractmethod
def method1(self):
pass
@abstractmethod
def method2(self):
pass
def start_common(self):
print('Template:start_common')
def stop_common(self):
print('Template:stop_common')
def run(self):
self.start_common()
self.method1()
self.method2()
self.stop_common()
class SubClassA(Template):
def method1(self):
print('SubClassA:method1')
def method2(self):
print('SubClassA:method2')
class SubClassB(Template):
def method1(self):
print('SubClassB:method1')
def method2(self):
print('SubClassB:method2')
if __name__ == '__main__':
s_a = SubClassA()
s_b = SubClassB()
s_a.run()
print('--------------------')
s_b.run()
実行結果:
Template:start_common
SubClassA:method1
SubClassA:method2
Template:stop_common
--------------------
Template:start_common
SubClassB:method1
SubClassB:method2
Template:stop_common
● Visitor パターン
Visitor.py
# ----------------------------------------------------------------------
# Visitor パターン
# ----------------------------------------------------------------------
# 機能をビジターに記述することで、処理の追加を簡単にします。
from abc import ABCMeta, abstractmethod
class AnimalElement(metaclass=ABCMeta):
@abstractmethod
def accept(self, visitor):
pass
class Visitor(metaclass=ABCMeta):
@abstractmethod
def visit_cat(self, cat_element):
pass
def visit_dog(self, dog_element):
pass
class CatElement(AnimalElement):
def accept(self, visitor):
visitor.visit_cat(self)
class DogElement(AnimalElement):
def accept(self, visitor):
visitor.visit_dog(self)
class OwnerVisitor(Visitor):
def visit_cat(self, cat_element):
print('visit_cat in OwnerVisitor')
print('Ownerビジターの処理:猫に餌をやるアクション')
def visit_dog(self, dog_element):
print('visit_dog in OwnerVisitor')
print('OwnerVisitorの処理:犬に餌をやるアクション')
class ChildVisitor(Visitor):
def visit_cat(self, cat_element):
print('visit_cat in ChildVisitor')
print('ChildVisitorの処理:猫に餌をやるアクション')
def visit_dog(self, dog_element):
print('visit_dog in ChildVisitor')
print('ChildVisitorの処理:犬に餌をやるアクション')
class Home(list):
def act(self, visitor):
for e in self:
e.accept(visitor)
if __name__ == '__main__':
home = Home()
home.append(CatElement())
home.append(DogElement())
home.act(OwnerVisitor())
print('-' * 50)
home.act(ChildVisitor())
実行結果:
visit_cat in OwnerVisitor
Ownerビジターの処理:猫に餌をやるアクション
visit_dog in OwnerVisitor
OwnerVisitorの処理:犬に餌をやるアクション
--------------------------------------------------
visit_cat in ChildVisitor
ChildVisitorの処理:猫に餌をやるアクション
visit_dog in ChildVisitor
ChildVisitorの処理:犬に餌をやるアクション
その他のデザインパターン
Pythonで生成に関するデザインパターンを作成してみた
Pythonで構造に関するデザインパターンを作成してみた