具有相同接口的两个模块或具有相同接口的两个 类 模块的优势?
Advantages to two modules with same interface or two classes with the same interface?
例如,我可以创建两个具有 f()
的模块(Mod1
和 Mod2
)。或者我可以创建两个实现 f()
.
的 classes
然后我可以
if condition:
import Mod1 as m
else:
import Mod2 as m
m.f()
或
if condition:
m = Class1()
else:
m = Class2()
m.f()
显然,如果我想存储任何状态,我需要使用 classes,但如果我只是使用 class 方法,那么这两种方法是否比另一种方法有优势?
编辑: 我主要关心 maintainability/extensibility/readability 而不是运行时性能。
总体思路
在您的特定情况下,您可以使用简单的模块级功能,而不是让一切都过于复杂。但就您对一般情况感兴趣而言,我建议您使用 Abstract Factory pattern。这是一个示例解决方案:
class YourAbstractFactory(object):
@classmethod
def get_factory(cls, condition):
cond_map = {
'impl1': Impl1,
'impl2': Impl2
}
impl = cond_map.get(condition)
return impl() if impl else None
def f1(self):
pass
def f2(self):
pass
YourAbstractFacotry
class 显然是一个抽象 class,它简单地定义了要实现的接口,即你的 f
函数的集合。此外,它定义并实现 get_factory
class 方法,returns 适当的实现,具体取决于条件。
class Impl1(YourAbstractFactory):
def f1(self):
print('Impl1.f1')
def f2(self):
print('Impl1.f2')
class Impl2(YourAbstractFactory):
def f1(self):
print('Impl2.f1')
def f2(self):
print('Impl2.f2')
以上class是你的接口的两个独立实现。他们之间互不知情,可以独立存在。
# This is where you put your condition, and get appropriate instance
>>> impl = YourAbstractFactory.get_factory('impl2')
>>> impl.f1()
Impl2.f1
因此,在一般情况下,此解决方案的优势在于您的客户端代码将与您的实现分离。意思是,您只会通过条件并获得所需的实现,并且对客户端代码中的实现没有任何想法和依赖性。唯一知道接口的具体实现的是get_factory
方法,它易于维护。
其他改进
为了进一步增强此解决方案并提高安全性(尽管 Python 是成人语言 ;)),您还可以使用 abc
module, with its ABCMeta
metaclass and abstractmethod
装饰器,以防止初始化 classes 没有实现所有的接口。在这种情况下,您需要像这样定义工厂 class。
from abc import ABCMeta, abstractmethod
class YourAbstractFactory(object):
__metaclass__ = ABCMeta
@classmethod
def get_factory(cls, condition):
cond_map = {
'impl1': Impl1,
'impl2': Impl2
}
impl = cond_map.get(condition)
return impl() if impl else None
@abstractmethod
def f1(self):
pass
@abstractmethod
def f2(self):
pass
例如,我可以创建两个具有 f()
的模块(Mod1
和 Mod2
)。或者我可以创建两个实现 f()
.
然后我可以
if condition:
import Mod1 as m
else:
import Mod2 as m
m.f()
或
if condition:
m = Class1()
else:
m = Class2()
m.f()
显然,如果我想存储任何状态,我需要使用 classes,但如果我只是使用 class 方法,那么这两种方法是否比另一种方法有优势?
编辑: 我主要关心 maintainability/extensibility/readability 而不是运行时性能。
总体思路
在您的特定情况下,您可以使用简单的模块级功能,而不是让一切都过于复杂。但就您对一般情况感兴趣而言,我建议您使用 Abstract Factory pattern。这是一个示例解决方案:
class YourAbstractFactory(object):
@classmethod
def get_factory(cls, condition):
cond_map = {
'impl1': Impl1,
'impl2': Impl2
}
impl = cond_map.get(condition)
return impl() if impl else None
def f1(self):
pass
def f2(self):
pass
YourAbstractFacotry
class 显然是一个抽象 class,它简单地定义了要实现的接口,即你的 f
函数的集合。此外,它定义并实现 get_factory
class 方法,returns 适当的实现,具体取决于条件。
class Impl1(YourAbstractFactory):
def f1(self):
print('Impl1.f1')
def f2(self):
print('Impl1.f2')
class Impl2(YourAbstractFactory):
def f1(self):
print('Impl2.f1')
def f2(self):
print('Impl2.f2')
以上class是你的接口的两个独立实现。他们之间互不知情,可以独立存在。
# This is where you put your condition, and get appropriate instance
>>> impl = YourAbstractFactory.get_factory('impl2')
>>> impl.f1()
Impl2.f1
因此,在一般情况下,此解决方案的优势在于您的客户端代码将与您的实现分离。意思是,您只会通过条件并获得所需的实现,并且对客户端代码中的实现没有任何想法和依赖性。唯一知道接口的具体实现的是get_factory
方法,它易于维护。
其他改进
为了进一步增强此解决方案并提高安全性(尽管 Python 是成人语言 ;)),您还可以使用 abc
module, with its ABCMeta
metaclass and abstractmethod
装饰器,以防止初始化 classes 没有实现所有的接口。在这种情况下,您需要像这样定义工厂 class。
from abc import ABCMeta, abstractmethod
class YourAbstractFactory(object):
__metaclass__ = ABCMeta
@classmethod
def get_factory(cls, condition):
cond_map = {
'impl1': Impl1,
'impl2': Impl2
}
impl = cond_map.get(condition)
return impl() if impl else None
@abstractmethod
def f1(self):
pass
@abstractmethod
def f2(self):
pass