在一个班级必须依赖其他因素的情况下,我很困惑。
例如
class Storage:
def __init__(self):
self.logger = Logger()
self.client = Elasticsearch()
def index(document):
try:
self.client.index(document)
except ElasticsearchException as e:
self.logger.error(str(e))
这里我的类必须有logger和Elasticsearch
对象来执行其操作。如何在可能有两种情况需要更改我的类的情况下如何维护SRP,例如:
有人可能会争辩说,我应该让客户端类处理异常,而不是记录在这里。但是在客户端只是 yield
要插入的文档并且接受索引操作失败的情况下,客户端类不会对错误感到烦恼。此外,即使我将异常重新抛出到客户端类,也会出现相同的SRP问题。
我很感激在我的背景下给出解释性答案。
答案 0 :(得分:2)
您可以通过引入其他层来为此功能定义抽象API:一个用于数据库,另一个用于执行日志记录。完成此操作后,您的Storage
课程必须仅限于使用它们,而不是直接打电话或任何真实的课程。特定库或模块暴露的方法。
这样他们(以及他们的客户喜欢重写的Storage
类)就不需要改变,除非由于某种原因必须改变其中一个抽象接口(如果由于某些原因必须改变它它的设计很好)。这两个抽象接口中的任何一个的任何具体实现都只有一个责任(即通过某些特定日志或数据库库中可用的内容来模拟抽象API)。
答案 1 :(得分:2)
我认为问题的一部分在标题中:“..具有多个依赖性”。您的依赖项是高度耦合的,因为在您的Storage类中实例化。 这就是为什么我会使用依赖注入(我有0 python知识,可能是一些错字):
interface StorageClientInterface:
def index(document)
interface LoggerInterface:
def error(Exception e)
class ElasticSearchStorage implements storageClientInterface:
def index(document):
// implements ElasticSearch specific storage logic
class MyDefaultLogger implements LoggerInterface:
def error(Exception e):
// implements MyDefaultLogger specific logging logic, totally agnostic from ElascticSearch
class Storage:
def __init__(self, StorageClientInterface storageClient, LoggerInterface logger):
self.client = storageClient
self.logger = logger
def index(document):
try:
self.client.index(document)
except Exception as e:
self.logger.error(e)
// usage
elasticSearch = ElasticSearch()
logger = MyDefaultLogger()
document = Document();
storage = Storage(elasticSearch, logger)
storage.index(document)
通过这种方式,您的Storage类不会与您的存储策略或日志记录策略相关联。它只知道它可以使用这两个接口。如果更改数据库,则只要此新存储策略实现StorageClientInterface,就不必更改Storage类中的任何内容。如果您更改记录错误的方式也是如此。只需实例化一个新的具体Logger,然后注入它。
答案 2 :(得分:0)
您可以实现此目的的一种方法是使用decorator模式。装饰器模式允许您将所有错误处理逻辑封装在一个单独的类中,然后可以用它来实际包装装饰类的行为,在本例中它将是您的Storage类。我不太了解Python,所以请原谅任何语法错误,但它看起来像这样:
class Storage:
def __init__(self, storageClient):
self.client = storageClient
def index(document):
self.client.index(document)
class ElasticSearchExceptionPolicy:
def __init__(self, decorated, logger):
self.logger = logger
self.decorated = decorated
def index(document):
try:
decorated.index(document)
except ElasticsearchException as e:
self.logger.error(str(e))
然后可以像这样使用这些对象:
elasticSearch = ElasticSearch()
logger = Logger()
storage = Storage(elasticSearch)
loggedStorage = ElasticSearchExceptionPolicy(storage, logger)
loggedStorage.index(document)
如果您想遵循开放/封闭原则,您可能还希望将ElasticSearch对象和Logger对象传递到各自的类中。