【问题标题】:Best-practice way to make two coupled classes interact使两个耦合类交互的最佳实践方法
【发布时间】:2018-05-17 15:55:00
【问题描述】:

我在以原则良好的面向对象方式组织我的代码时遇到了麻烦。

总结:我希望有两个单独的类,每个类都实现自己的功能(例如分别模拟和绘图),但以某种方式将它们组合起来(以可扩展的方式!)拥有一个实例实现它们的两个功能。

示例:假设我有一个生成数据的类

class DataSimulator():
    def __init__(self, N):
        self.N = N
        self.result = None

    def simulate(self):
        self.result = range(self.N) #imagine lots of simulation code here

我还想绘制我的数据。我可以简单地将plot() 方法添加到DataSimulator 但是

  • 我认为DataPlotter 应该是它自己独立的类,因为它的功能与DataSimulator 的功能完全不同。

A. 我想出的一个选项是一个单独的类,它存储一个 DataSimulator 实例,然后根据需要绘制它

class DataPlotter():
    def __init__(self, data_simulator_instance):
        self.d = data_simulator_instance

    def plot(self):
        plt.plot(self.d.result) #e.g. using matplotlib

dataSim = DataSimulator(5)
dataPlt = DataPlotter(dataSim)    
dataSim.simulate()
dataPlt.plot()

但是,为了使用这个范式;

  • 我需要始终跟踪两个独立的紧密耦合对象。这似乎是不好的做法。我永远不会没有另一个,所以我想将它们的功能合二为一。

B. 我考虑让DataPlotter 继承自DataSimulator,如下所示:

class DataPlotter(DataSimulator):        
    def plot(self):
        plt.plot(self.result) 

dataPlt = DataPlotter(5)
dataPlt.simulate()
dataPlt.plot()

这很好,因为我现在只有一个实例可以满足我的所有需求,但这似乎仍然是错误的,因为:

  • DataPlotter 实例执行模拟例程令人困惑
  • 如果我写了DataSimulatorVersion2,我就不能重复使用我的DataPlotter

C.同样我也考虑过DataSimulator继承自DataPlotter

class DataPlotter():        
    def plot(self):
        plt.plot(self.result)  

class DataSimulator(DataPlotter):
    def __init__(self, N):
        self.N = N
        self.result = None

    def simulate(self):
        #lots of simulation code here
        self.result = range(self.N)

dataSim = DataSimulator(5)
dataSim.simulate()
dataSim.plot() 

这解决了上面的第一个问题(我认为模拟器绘制数据是有意义的,但绘图仪模拟数据却不是)但是现在

  • 如果我写一个DataPlotterVersion2,我就不能重用DataSimulator
  • DataPlotter 中使用self.result 而不保证变量存在似乎也是不好的做法。

我的问题:

  1. 是否有解决此问题的最佳实践方法? (我在顶部的摘要中写的实际上是我想要的,还是应该走完全不同的路线?)
  2. 我提出的问题(在要点中)是否真的有效?

【问题讨论】:

标签: python class oop project-organization


【解决方案1】:

我认为列出的这些方法都不是正确的答案。模拟器的目的是产生数据,绘图仪的目的是消费和使用它——数据是这里的另一个对象。绘图仪不是模拟器,模拟器也不是绘图仪,理论上两者都不需要另一个存在,因此它们没有is-a或has-a关系。 OOP 旨在使用对象来表示您正在使用的实际事物。我会建议添加另一个 Data 类,即使它只是数组的包装器或类似简单的东西,你的 Simulator 类输出并且你的 Plotter 类作为输入。

关于子弹—— 1. 是的,当然 2. 如果它们如此紧密耦合,请考虑使用数据管理器对象而不是名为绘图仪或模拟器的对象,因为从意识形态上讲,它更接近于一个做两件事的对象,而不是两个做一件事的对象。如果您需要 v2,您可以从它继承并覆盖执行绘图/模拟的方法之一。 3,4,5,6。你是对的,出于你描述的原因,这些都是坏主意。

【讨论】:

    【解决方案2】:

    在我看来,我会像您在第一个实现中提到的那样使其尽可能简单:两个独立的类。 DataPlotter 可以绘制任何类型的数据,不仅是 DataSimulator,因为 python 不检查可以传递任何其他对象的类型。唯一的限制是这个对象需要一个适合 'plt.plot' 函数的 'result' 属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-24
      • 2011-04-07
      • 2019-09-18
      • 2016-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-07
      相关资源
      最近更新 更多