Python基礎 オブジェクト指向23(Interpreter) 振る舞いに関するデザインパターン
| 登録日 | :2026/02/07 18:31 |
|---|---|
| カテゴリ | :Python基礎 |
(オブジェクトの種類)
構文の解析を行なって、その結果を利用して処理を行うパターン
-
解析を行うための「規則」をクラスとして表現
-
規則のツリー構造を扱うことができる
構成要素
Context
- 解析を行いたい値や情報を提供するクラス
AbstractExpression
-
規則を表す抽象クラスもしくはインターフェース
-
規則が解析を行うための共通APIを定義
NonterminalExpression
-
AbstractExpressionを継承(実装)する子クラス
-
具体的な規則を実装
-
内部にAbstractExpression型のオブジェクトを保持することで、規則の親子関係を表現
TerminalExpression
-
AbstractExpressionを継承(実装)する子クラス
-
具体的な規則を実装
-
末端の規則を表す
オブジェクト指向的要素
- ポリモーフィズムを利用したパターン
AbstractExpressionでクライアントに対してアクセスさせるための共通APIを定義
NonterminalExpressionは内部にAbstractExpression型のオブジェクトを保持
クライアントやNonterminalExpressionは、共通APIを使用することで具体的な実装を意識する必要がなくなる
TerminalExpressionやNonTerminalExpressioinの追加・削除・切り替え等が可能
メリット・デメリット
メリット
- 既存のコードを修正することなく、規則の追加・拡張が可能
デメリット
- シンプルな規則を実現する場合、コードがより複雑になる可能性がある
使い所
特定の文法で記述された内容を解析して処理したい場合
-
正規表現
-
SQL解析
-
プログラミング言語開発
サンプル
例)日付型をフォーマットする例(YYYY-MM-DD)
from abc import ABC, abstractmethod
import datetime
import re
class Context(object):
def __init__(self, expression: str, date: datetime.date):
self.validate(expression)
self.expression = expression
self.date = date
def validate(self, expression: str):
if len(expression) != 10 or not bool(re.match(
"(?=.*YYYY)(?=.*MM)(?=.*DD)", expression
)):
raise Exception("[ERROR] Wrong Expression.")
class AbstractExpression(ABC):
@abstractmethod
def interpret(self, context: Context):
pass
class YearExpression(AbstractExpression):
def __init__(self):
self.__child = None
def set_child(self, child: AbstractExpression):
self.__child = child
def interpret(self, context: Context):
expression = context.expression
year = context.date.year
context.expression = expression.replace("YYYY", str(year))
if self.__child:
self.__child.interpret(context)
return context
class MonthExpression(AbstractExpression):
def __init__(self):
self.__child = None
def set_child(self, child: AbstractExpression):
self.__child = child
def interpret(self, context: Context):
expression = context.expression
month = context.date.month
context.expression = expression.replace("MM", str(month).zfill(2))
if self.__child:
self.__child.interpret(context)
return context
class DayExpression(AbstractExpression):
def __init__(self):
self.__child = None
def set_child(self, child: AbstractExpression):
self.__child = child
def interpret(self, context: Context):
expression = context.expression
day = context.date.day
context.expression = expression.replace("DD", str(day).zfill(2))
if self.__child:
self.__child.interpret(context)
return context
if __name__ == '__main__':
now_date = datetime.datetime.now().date()
expression = "MM/DD/YYYY"
context = Context(expression, now_date)
year_expression = YearExpression()
month_expression = MonthExpression()
day_expression = DayExpression()
month_expression.set_child(day_expression)
year_expression.set_child(month_expression)
result = year_expression.interpret(context)
print(now_date.strftime("%m/%d/%Y"))
print(result.expression)