ООП Дизайн - В Python это качественный ОО дизайн или эпический провал? - PullRequest
1 голос
/ 21 января 2010

В системе, которая принимает заказы, в которых есть платежи, в которых есть транзакции шлюза, если объекты будут такими:

class Order(object):
        ... Inside init ...
        self.total_in_dollars = <Dollar Amount>
        self.is_paid = <Boolean Value>

class Payment(object):
        ... Inside init ...
        self.order = order_instance
        self.amount = order.total_in_dollars

class GatewayTransaction(object):
        ... Inside init ...
        self.payment = payment_instance
        self.amount = <Dollar Amount>

Кажется, это был бы способ сделать это (очевидно, это не реальный код с целочисленными суммами в долларах и т. Д., Но вы получите картину). Я сделал это так, потому что заказ может существовать без оплаты , а платеж может существовать до того, как произойдет фактическая транзакция PayPal . Вам этого не хватает? Я в своем мышлении назад?

ИЛИ , Должно ли это быть так:

class GatewayTransaction(object):
    payment = payment_instance
    amount = <Dollar Amount>

class Payment(object):
    amount = <Dollar Amount>
    gateway_transaction = gateway_transaction_instance

class Order(object):
    amount_in_dollars = <Dollar Amount>
    payment = payment_instance

Ответы [ 3 ]

6 голосов
/ 21 января 2010

Похоже, вы присваиваете переменные instance как class переменные, что, безусловно, является неправильной тактикой. Таким образом, переменные должны быть self.total_in_dollars (например, Order) и т. Д., Назначенные в __init__, , а не переменные класса, назначенные в операторе class!

Простое создание экземпляра Order без соответствующего Payment - это нормально (и, очевидно, следует установить is_paid в False), основываясь только на общем количестве (и, возможно, некотором числовом идентификаторе, чтобы клиенты и клиенты могли в дальнейшем см. конкретный заказ).

Не дублируйте информацию без необходимости! Поскольку экземпляр Payment всегда будет иметь ссылку на экземпляр Order, он должен , а не скопировать self.order.total_in_dollars в self.amount - лучше иметь эту информацию в one place (вы можете сделать readonly property, если хотите получить к нему хороший доступ); и тем более для экземпляров транзакции.

Если экземпляр Order переносит дополнительные метаданные, которые влияют на то, как создается и ведет себя соответствующий экземпляр Payment, это нормально, но настоятельно рекомендует сделать создание экземпляра Payment заданием фабричного метода класса Object (который затем может также отслеживайте уже сгенерированные экземпляры и убедитесь, что для одного данного экземпляра Заказа никогда не будет более одного экземпляра Payment.

Редактировать : теперь, когда ОП несколько отредактировал букву А, я могу подтвердить мнение, что зависимости в первой версии примерно верны (за исключением того, что количество не должно копироваться по всему место), и те, что во вторых версиях, prima facie, не верны (например, наличие взаимной / круговой зависимости всегда является запахом проекта, если только это явно и недвусмысленно не оправдано потребностями специального приложения - даже когда необходимо перейти назад и четвертое существует, по крайней мере, одна из двух ссылок должна быть слабой ссылкой.

Редактировать : поскольку ОП явно просит больше подробностей о заводском методе, который я предложил, я имел в виду что-то вроде этого:

import weakref

class Payment(object):
  def __init__(self, order):
    self.order = weakref.proxy(order, self.ordergone)
  def ordergone(self, *_):
    self.order = None
  @property
  def amount(self):
    if self.order is None: return None
    else: return self.order.total_in_dollars

class Order(object):
  def __init__(self, amount):
    self.total_in_dollars = amount
    self.is_paid = False
    self._payment = None
  @property
  def payment(self):
    if self._payment is None:
      self._payment = Payment(self)
    return self._payment
2 голосов
/ 21 января 2010

Я бы подошел к этому по-другому - написав некоторый код для работы с заказами, платежами и т. Д. Это прояснит мои потребности в дизайне, например, получится, что Payment.amount может быть больше, чем Order.total_in_dollars, из-за некоторой обработкисборы.Но тогда может оказаться, что, возможно, эти сборы за обработку должны храниться отдельно, или даже они могут / должны иметь свою собственную модель.И да, это TDD .

2 голосов
/ 21 января 2010

Дайте конструкторам объектов, которые принимают соответствующий другой объект, на который вы хотите, чтобы он ссылался, затем превратите поля в свойства, которые проверяют тип, который вы им назначаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...