设计模式十三:解释器模式
什么是解释器模式
主要放向:让非初级用户和领域专家使用一门简单的语言来表达想法
一般是高级用户才会有所兴趣。
典型案例
音乐演奏者是现实中解释器模式的例子,
五线谱图形化地表达了声音的音调和持续时间(音乐语言)
音乐演奏者能根据五线谱的符合精确重现声音(语言解释器)
补充知识
领域特定语言(Domain Specific Language ,DSL):针对一个特定领域的有限表达能力的计算机语言。
巴科斯-诺尔形式定义简单语法:
event ::= command token receiver token arguments
command ::= word+
word ::= a collection of one or more alphanumeric characters
token ::= ->
receiver ::= word+
arguments ::= word+
实例代码
from pyparsing import Word,OneOrMore,Optional,Group,Suppress,alphanums
class Gate:
def __init__(self):
self.is_open = False
def __str__(self):
return 'open' if self.is_open else 'closed'
def open(self):
print('opening the gate')
self.is_open = True
def close(self):
print('closing the gate')
self.is_open = False
class Garage:
def __init__(self):
self.is_open = False
def __str__(self):
return 'open' if self.is_open else 'closed'
def open(self):
print('opening the garage')
self.is_open = True
def close(self):
print('closing the garage')
self.is_open = False
class Aircondition:
def __init__(self):
self.is_on = False
def __str__(self):
return 'on' if self.is_on else 'off'
def turn_on(self):
print('turning on the aircondition')
self.is_open = True
def turn_off(self):
print('turning off the aircondition')
self.is_open = False
class Heating:
def __init__(self):
self.is_on = False
def __str__(self):
return 'on' if self.is_on else 'off'
def turn_on(self):
print('turning on the heating')
self.is_open = True
def turn_off(self):
print('turning off the heating')
self.is_open = False
class Boiler:
def __init__(self):
self.temperature = 83
def __str__(self):
return 'boiler temperature : {}'.format(self.temperature)
def increase_temperature(self,amount):
print('increasing the boiler`s temperature by {} degrees'.format(amount))
self.temperature += amount
def decrease_temperature(self,amount):
print('decreasing the boiler`s temperature by {} degrees'.format(amount))
self.temperature -= amount
class Fridge:
def __init__(self):
self.temperature = 2
def __str__(self):
return 'fridge temperature: {}'.format(self.temperature)
def increase_temperature(self,amount):
print('increasing the fridge`s temperature by {} degrees'.format(amount))
self.temperature += amount
def decrease_temperature(self,amount):
print('decreasing the fridge`s temperature by {} degrees'.format(amount))
self.temperature -= amount
def main():
# 巴科斯-诺尔形式定义简单语法
word = Word(alphanums)
command= Group(OneOrMore(word))
token = Suppress("->")
device = Group(OneOrMore(word))
argument = Group(OneOrMore(word))
event = command + token + device + Optional(token + argument)
# 实例类
gate = Gate()
garage = Garage()
airco = Aircondition()
heating = Heating()
boiler = Boiler()
fridge = Fridge()
# 使用语法
tests = ('open -> gate',
'close -> garage',
'turn on -> aircondition',
'turn off -> heating',
'increase -> boiler temperature -> 5 degrees',
'decrease -> fridge temperature -> 2 degrees')
# 解释语法1
open_actions = {
'gate':gate.open,
'garage':garage.open,
'aircondition':airco.turn_on,
'heating':heating.turn_on,
'boiler temperature':boiler.increase_temperature,
'fridge temperature':fridge.increase_temperature
}
# 解释语法2
close_actions = {
'gate':gate.close,
'garage':garage.close,
'aircondition':airco.turn_off,
'heating':heating.turn_off,
'boiler temperature':boiler.decrease_temperature,
'fridge temperature':fridge.decrease_temperature
}
# 分析语言
for t in tests:
if len(event.parseString(t))==2: # 不带参数
cmd,dev = event.parseString(t) # ['turn', 'on'] ['aircondition']
cmd_str,dev_str = ' '.join(cmd),' '.join(dev) # 需要以 空格 隔开
if 'open' in cmd_str or 'turn on' in cmd_str:
open_actions[dev_str]()
elif 'close' in cmd_str or 'turn off' in cmd_str:
close_actions[dev_str]()
elif len(event.parseString(t))==3: # 带参数
cmd,dev,arg = event.parseString(t) # ['increase'] ['boiler', 'temperature'] ['5', 'degrees']
cmd_str,dev_str,arg_str = ' '.join(cmd),' '.join(dev),' '.join(arg) # 需要以 空格 隔开
num_arg = 0
try:
num_arg = int(arg_str.split()[0])
except ValueError as err:
print("expected number but got: '{}'".format(arg_str[0]))
if 'increase' in cmd_str and num_arg > 0:
open_actions[dev_str](num_arg)
elif 'decrease' in cmd_str and num_arg > 0:
close_actions[dev_str](num_arg)
if __name__ == "__main__":
main()