2013-02-23 112 views
0

这是一个丑陋的高维护工厂。我真的只需要一种方法来使用字符串实例化一个名称与字符串匹配的对象。我认为元类是答案,但我无法弄清楚如何使用它:必须有更好的方法来做到这一点

from commands.shVersionCmd import shVersionCmd 
from commands.shVRFCmd import shVRFCmd 
def CommandFactory(commandnode): 
    if commandnode.attrib['name'] == 'shVersionCmd': return shVersionCmd(commandnode)   
    if commandnode.attrib['name'] == 'shVRFCmd': return shVRFCmd(commandnode) 
+2

也许你希望将标题更改为“通话功能”按名称“?也许你可以尝试谷歌呢? ;) – 2013-02-23 13:14:09

+0

我可能有一个研究失败,但我可以充满信心地说,这不是因为缺乏尝试。感谢关键字提示虽然:) – mnate 2013-02-25 13:34:26

回答

2

你可以看一下全球的名字干净调用的代码块:

from commands.shVersionCmd import shVersionCmd 
from commands.shVRFCmd import shVRFCmd 

# An explicit list of allowed commands to prevent malicious activity. 
commands = ['shVersionCmd', 'shVRFCmd'] 

def CommandFactory(commandnode): 
    cmd = commandnode.attrib['name'] 
    if cmd in commands: 
     fn = globals()[cmd] 
     fn(commandnode) 
+0

此解决方案的一个问题:如果'cmd'它不*在'commands'中,它只是返回而不会引发异常。易于修复,但容易错过。你需要在'fn(commandnode)'之前添加'return'。 – 2013-02-23 14:12:43

+0

的确如此,但最初显示的代码也是如此。我不想为这种情况发明一种行为。 – 2013-02-23 14:16:28

+0

只需确认:shVersionCmd和shVRFCdm是类(不是函数),没关系?感谢这一点。我以前没见过全局变量。 – mnate 2013-02-25 13:29:02

0

eval是你的朋友:

from commands import * 
def CommandFactory(commandnode): 
    name=commandnode.attrib['name'] 
    assert name in ("shVersionCmd", "shVRFCmd"), "illegal command" 
    return eval(name+"."+name)(commandnode) 

请注意,如果你是肯定name永远不会包含任何非法命令,你可能会删除assert并把功能变成一个无需维护的喜悦。如有疑问,请将其保留并保存在一个地方。

+1

eval很少是一个好主意,并将漏洞引入到您的程序中。 – 2013-02-23 13:38:55

+0

因此,向我们展示*您的*解决方案。 'eval'是一个功能,是的,它可能是危险的。这并不意味着它没用。你听起来好像它总是引入漏洞,但事实并非如此,它取决于'commandnode.attrib ['name']'的来源。 – 2013-02-23 13:44:22

+0

不,这不是无用的,但它是一个容易过度使用的大钝头锤。 'globals()'在这里就够了。 – 2013-02-23 13:47:44

0

我个人的偏好会是转变工厂和命令实现之间的依赖关系,这样每个命令都会在工厂注册。

实现示例:

文件命令/ __ init__.py:

import pkgutil 
import commands 

_commands = {} 

def command(commandCls): 
    _commands[commandCls.__name__] = commandCls 
    return commandCls 

def CommandFactory(commandnode): 
    name = commandnode.attrib['name'] 
    if name in _commands.keys(): 
     return _commands[name](commandnode) 

# Load all commands 
for loader, module_name, is_pkg in pkgutil.walk_packages(commands.__path__): 
    if module_name!=__name__: 
     module = loader.find_module(module_name).load_module(module_name) 

文件命令/ mycommand.py:

from commands import command 

@command 
class MyCommand(object):  
    def __init__(self, commandnode): 
     pass 

小测试:

from commands import CommandFactory 

# Stub node implementation 
class Node(object): 
    def __init__(self, name): 
     self.attrib = { "name": name } 

if __name__=='__main__': 
    cmd = CommandFactory(Node("MyCommand")) 
    assert cmd.__class__.__name__=="MyCommand", "New command is instance of MyCommand" 
    cmd = CommandFactory(Node("UnknownCommand")) 
    assert cmd is None, "Returns None for unknown command type" 
相关问题