代码之家  ›  专栏  ›  技术社区  ›  Richard Levasseur

什么使静态初始化函数好,坏,或其他?

  •  1
  • Richard Levasseur  · 技术社区  · 15 年前

    假设您有这样的代码:

    _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()...
    

    对我来说,这是一个不好的模式,一些缺点:

    1. Doer 可以在不满足其前提条件的情况下创建
    2. 代码不容易测试,因为ConnPool不能直接模拟出来。
    3. Init 必须在第一次就打电话。如果它发生了变化,因此可以多次调用,则必须添加额外的逻辑来检查变量是否已经定义,并且必须传递大量空值以跳过重新初始化。
    4. 在线程的情况下,通过添加锁,上述操作变得更加复杂

    另一方面,一些优点:

    1. Init(5, "user/pass", 2, "user/pass")
    2. 简单又“干净”

    就我个人而言,我认为弊大于利,也就是说,可测试性和有保证的前提条件大于简单和方便。

    1 回复  |  直到 15 年前
        1
  •  2
  •   dash-tom-bang    15 年前

    在我看来,这个例子的唯一问题是全局状态的使用。所以别那么做。

    说真的-当你担心的问题出现时,通过将适当的上下文传递给实干家来解决。在某些情况下,“适当的上下文”可能是几个简单的参数(例如,一个读卡器列表和一个写卡器列表),也可能是一个更复杂的聚合对象(“连接管理器”,可以在引用它的任何人的外部添加和删除连接)。

    要明确指出你的缺点:

    1. 如果行为人有先决条件,则验证它们。如果他们没有被满足,提出一个例外。
    2. 使Init创建将传递给Doer的东西,而不是创建全局数据。对于嘲弄,通过类也要建立?基本上,使用某种工厂。
    3. 如果线程是共享的,您只需要担心它在您的状态下的安全性。如果每个线程都有自己的连接管理器(例如),那么在这个级别没有什么可以锁定的。

    所以-这样做并不是特别不方便:

    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
          ...