Python デザインパターン サンプルコード State
結城 浩「Java言語で学ぶデザインパターン入門」をPython化
Python3(3.11)で動くソースコード(.pyファイル .ipynbファイル)あります
「anaconda3」on .py「PyCharm」.ipynb「Jupyter Notebook」
(2023-11-19)Python3.11で動作確認済み
State Context (doClock, doUse, (setClock, changeState, doAlarm, doPhone) callSecurityCenter, recordLog) ↑ ↑ ↑ DayState NightState SafeFrame (getInstance, do.) (getInstance, do.) (do.)class State, class Context は,抽象メソッドでありテンプレートです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import sys import time import tkinter.scrolledtext import tkinter as Tk from abc import ABCMeta, abstractmethod class State(metaclass = ABCMeta): @abstractmethod def doClock(self, context, hour): # 時刻設定 pass @abstractmethod def doUse(self, context): # 金庫使用 pass @abstractmethod def doAlarm(self, context): # 非常ベル pass @abstractmethod def doPhone(self, context): # 通常通話 pass class DayState(State): def __new__(cls, *args, **kwargs): if not hasattr(cls, "__instance__"): cls.__instance__ = super(DayState, cls).__new__(cls, *args, **kwargs) return cls.__instance__ def getInstance(): # 唯一のインスタンスを得る return DayState().__instance__ def doClock(self, context, hour): # 時刻設定 if (hour < 9 or 17 <= hour): context.changeState(NightState.getInstance()) def doUse(self, context): # 金庫使用 context.recordLog("金庫使用(昼間)") def doAlarm(self, context): # 非常ベル context.callSecurityCenter("非常ベル(昼間)") def doPhone(self, context): # 通常通話 context.callSecurityCenter("通常の通話(昼間)") def __str__(self): # インスタンスをprintすると呼ばれます return "[昼間]"; class NightState(State): def __new__(cls, *args, **kwargs): if not hasattr(cls, "__instance__"): cls.__instance__ = \ super(NightState, cls).__new__(cls, *args, **kwargs) return cls.__instance__ def getInstance(): # 唯一のインスタンスを得る return NightState().__instance__ def doClock(self, context, hour): # 時刻設定 if (9 <= hour and hour < 17): context.changeState(DayState.getInstance()); def doUse(self, context): # 金庫使用 context.callSecurityCenter("非常:夜間の金庫使用!"); def doAlarm(self, context): # 非常ベル context.callSecurityCenter("非常ベル(夜間)"); def doPhone(self, context): # 通常通話 context.recordLog("夜間の通話録音"); def __str__(self): # インスタンスをprintすると呼ばれます return "[夜間]"; class Context(metaclass = ABCMeta): @abstractmethod def setClock(self, hour): # 時刻の設定 pass @abstractmethod def changeState(self, state): # 状態変化 pass @abstractmethod def callSecurityCenter(self, msg): # 警備センター警備員呼び出し pass @abstractmethod def recordLog(self, msg): # 警備センター記録 pass class SafeFrame(Tk.Frame, Context): # コンストラクタ def __init__(self, master=None): # tkinter Tk.Frame.__init__(self, master, bg='light gray') self.master.title('State Sample') self.file_name=None # 時計 self.Clock = Tk.StringVar() textClock = Tk.Label( self, textvariable=self.Clock, font=('MS ゴシック', 12), bg='light gray', width=20) textClock.pack() # 掲示板 self.Screen = Tk.scrolledtext.ScrolledText( self, font=('MS ゴシック', 12), width=25, height=16) self.Screen.pack(fill=Tk.BOTH, expand=1) self.Screen.focus_set() # 押しボタン self.footer_area = Tk.Frame(self, bg='light gray') self.footer_area.pack() self.start_button = Tk.Button( self.footer_area, text="Clock+", bg='light gray', width=8, font=('Times', 10), command=self.clock_plus) self.start_button.pack(side=Tk.LEFT, padx=5,pady=5) self.a_button = Tk.Button( self.footer_area, text="金庫使用", bg='light gray', width=8, font=('Times', 10), command=self.buttonUse) self.a_button.pack(side=Tk.LEFT, padx=5,pady=5) self.b_button = Tk.Button( self.footer_area, text="非常ベル", bg='light gray', width=8, font=('Times', 10), command=self.buttonAlarm) self.b_button.pack(side=Tk.LEFT, padx=5,pady=5) self.c_button = Tk.Button( self.footer_area, text="通常通話", bg='light gray', width=8, font=('Times', 10), command=self.buttonPhone) self.c_button.pack(side=Tk.LEFT, padx=5,pady=5) self.d_button = Tk.Button( self.footer_area, text="終了", bg='light gray', width=8, font=('Times', 10), command=self.buttonExit) self.d_button.pack(side=Tk.LEFT, padx=5,pady=5) # tkinter終り # メインルーチン self.state = DayState.getInstance() # 現在の状態 self.hour = 22 self.setClock(self.hour) # 最初に,昼→夜 # コンストラクタ終り def clock_plus(self): self.hour += 1 if self.hour == 24: self.hour = 0 self.setClock(self.hour) # ボタンが押されたらここに来る def buttonUse(self): #print("buttonUse") # debug self.state.doUse(self) def buttonAlarm(self): #print("buttonAlarm") # debug self.state.doAlarm(self) def buttonPhone(self): #print("buttonPhone") # debug self.state.doPhone(self) def buttonExit(self): print("sys.exit()") # bugります # 時刻の設定 def setClock(self, hour): #self.hour = hour clockstring = "現在時刻は"; if (hour < 10): clockstring += "0" + str(hour) + ":00"; else: clockstring += str(hour) + ":00"; #sys.stdout.write("{}\n".format(clockstring)) # debug self.Clock.set('ただいまの時間は {}:{}'.format(hour, "00")) self.state.doClock(self, hour) # 状態変化 def changeState(self, state): #sys.stdout.write("{}から{}へ状態が変化しました。\n" #.format(self.state, state)) # debug self.Screen.insert(Tk.END, "{}から{}へ状態が変化しました。\n" .format(self.state, state)) self.state = state # 警備センター警備員呼び出し def callSecurityCenter(self, msg): #sys.stdout.write("call! {}\n".format(msg)) # debug self.Screen.insert(Tk.END, "call! {}\n".format(msg)) # 警備センター記録 def recordLog(self, msg): #sys.stdout.write("record ... {}\n".format(msg)) # debug self.Screen.insert(Tk.END, "record ... {}\n".format(msg)) if __name__ == '__main__': app = SafeFrame() app.pack() app.mainloop()