假设您有如下代码:
_READERS = None
_WRITERS = None
def Init(num_readers, reader_params, num_writers, writer_params, ...args...):
...logic...
_READERS = new ReaderPool(num_readers, reader_params)
_WRITERS = new WriterPool(num_writers, writer_params)
...more logic...
class Doer:
def __init__(...args...):
...
def Read(self, ...args...):
c = _READERS.get()
try:
...work with conn
finally:
_READERS.put(c)
def Writer(...):
...similar to Read()...
对我来说,这是一个不好的模式,有一些缺点:
可以创建
Doer
而不满足其先决条件该代码不容易测试,因为不能直接模拟ConnPool。
Init
必须在第一次调用。如果更改了它以便可以多次调用,则必须添加额外的逻辑以检查是否已定义变量,并且必须传递大量NULL值以跳过重新初始化。如果出现线程,则通过添加锁定使上述操作变得更加复杂
全局变量并没有被用来传达状态(严格来说这不是很糟糕,但是有代码的味道)
另一方面,一些优点:
调用
Init(5, "user/pass", 2, "user/pass")
非常方便简单而“干净”
就我个人而言,我认为弊大于利,即可测试性和确定的前提条件胜过简单和方便。
最佳答案
在我看来,此示例的唯一问题是使用全局状态。所以不要那样做。
认真地说,当出现问题时,将适当的上下文传递给执行者,即可解决您担心的问题。在某些情况下,“适当的上下文”可能是几个简单的参数(例如,读者列表和作者列表),或者可能是更复杂的集合对象(“连接管理器”,可能在外部添加或删除了连接)给引用它的任何人)。
要明确解决您的缺点:
如果Doer有前提条件,请对其进行验证。如果不符合,请提出例外。
(如果将ConnPool作为参数传递给ctor或worker函数,则可以解决。)
让Init创建要传递给Doer的东西,而不是创建全局数据。对于嘲笑,是否也要通过课程?基本上,使用某种工厂。
如果共享状态,则只需要担心状态中的线程安全。如果每个线程都有自己的连接管理器(例如),那么在此级别没有什么可锁定的。
(如果不使用全局变量,则解决此问题。)
因此,这样做并非特别不方便:
class ConnPool:
def __init__(self, numReaders, readerParams, numWriters, writerParams):
(your InitFunction with a bunch of self. prepending)
class Doer:
def __init__(self, connPool, ...):
if not preconditions:
raise DoerPreconditionsNotMetError()
self.connections = connPool
def Read(self):
readers, writers = self.connections._READERS, self.connections._WRITERS
...
所以,我不知道。我认为这与您的示例相比没有那么简洁或可读性差。 (或者,您可以将连接管理器传递给Read函数,这显然可以满足您的要求。)