Наилучший способ взаимодействия двух связанных классов - PullRequest
0 голосов
/ 17 мая 2018

У меня возникают проблемы с организацией моего кода в принципиальной объектно-ориентированной форме.

В итоге : я хотел бы иметь два отдельных класса, каждый из которых реализует свою собственную функциональность (например,моделирование и построение графиков, соответственно), но каким-то образом объединить их (расширяемым образом!), чтобы один экземпляр реализовал обе их функциональности.

Пример: предположим, у меня есть класс, который генерирует данные

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

Это решает первую проблему, описанную выше (я думаю, что для симулятора имеет смысл отображать свои данные, но не для плоттера для имитации данных), но теперь

  • Я могуповторное использование DataSimulator, если я напишу DataPlotterVersion2
  • Использование self.result в DataPlotter без какой-либо гарантии, что переменная существует, также кажется плохой практикой.

Мой вопрос:

  1. Существует ли наилучший способ решения этой проблемы?(Является ли то, что я написал в сводке вверху, действительно тем, что я хочу, или я должен пойти совершенно другим путем?)
  2. Действительно ли проблемы, которые я поднял (в пунктах с маркерами), действительно актуальны?

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

Я думаю, что ни один из перечисленных подходов не является правильным ответом.Симулятор предназначен для получения данных, плоттер предназначен для их использования и использования - данные здесь являются еще одним объектом.Плоттер не является симулятором, и симулятор не является плоттером, и ни один из них в теории не нуждается в существовании другого, поэтому у них нет отношения «есть» или «есть».ООП предназначен для использования объектов для представления фактических вещей, с которыми вы работаете.Я бы даже предложил добавить еще один класс данных, даже если это просто оболочка вокруг массива или нечто подобное, что выводит ваш класс Simulator, а ваш класс Plotter принимает в качестве входных данных.

Что касаетсяпули - 1. да, точно 2. если они тесно связаны между собой, рассмотрите возможность использования объекта, который является менеджером данных, вместо того, что называется плоттером или симулятором, так как в идеологическом отношении он будет ближе к одному объекту, который выполняет две вещивместо двух, которые делают одну вещь.Если вам нужен v2, вы можете наследовать его и перезаписать один из методов, который выполняет построение / моделирование.3,4,5,6.Вы правы, это все плохие идеи по причинам, которые вы описали.

0 голосов
/ 17 мая 2018

По-моему, я бы хотел сделать это как можно более простым, как вы упомянули в своей первой реализации: два отдельных класса. DataPlotter может отображать любые данные, не только DataSimulator, так как python не проверяет типы, которые вы можете передавать любым другим объектам. Единственным ограничением является то, что этому объекту необходим атрибут «result», который подходит для функции «plt.plot».

...