ООП: Как написать питоническое взаимодействие между классами? - PullRequest
0 голосов
/ 07 января 2019

Я хотел бы смоделировать взаимодействие между двумя классами, где один из классов принимает другой в качестве аргумента в одном из своих методов. Какой класс должен быть в аргументе метода другого класса?

Я написал два альтернативных решения проблемы, но я не уверен, какой из них считается правильным способом решения этой проблемы. Может быть, есть даже лучший способ, но вот мои две альтернативы:

class BankAccount:

    def __init__(self, balance):
        self._balance = balance

    def transaction(self, cash):
        self._balance += cash._value
        cash._value = 0


class Cash:

    def __init__(self, value):
        self._value = value

    def transfer(self, bank_account):
        bank_account._balance += self._value
        self._value = 0


if __name__ == "__main__":

# First alternative
    acc = BankAccount(balance=100)
    cash = Cash(value=10)

    print('-' * 30)
    print('First alternative')
    print(f'Account balance before: {acc._balance}')
    print(f'Cash value before: {cash._value}')
    acc.transaction(cash=cash)
    print(f'Account balance after: {acc._balance}')
    print(f'Cash value after: {cash._value}')

# Second alternative
    acc = BankAccount(balance=100)
    cash = Cash(value=10)

    print('-' * 30)
    print('Second alternative')
    print(f'Account balance before: {acc._balance}')
    print(f'Cash value before: {cash._value}')
    cash.transfer(bank_account=acc)
    print(f'Account balance after: {acc._balance}')
    print(f'Cash value after: {cash._value}')

Как видите, обе альтернативы показывают одинаковые результаты, но я был бы рад получить рекомендацию по питоническому способу моделирования такого взаимодействия классов. Спасибо.

1 Ответ

0 голосов
/ 07 января 2019

Пример плохо сформирован, что не позволяет нам сконцентрироваться на реальном ООП. Некоторым наличным не имеет смысла терять свою стоимость, поскольку они передаются. Банкнота в 20 долларов теряет свою стоимость из-за того, что вы вносите ее в банк?

Новый пример

Вместо этого давайте рассмотрим проблему перевода денег между двумя банковскими счетами.

Ключевой концепцией ООП является то, что атрибуты экземпляра не должны обновляться напрямую. Вместо этого экземпляр должен предоставлять API через методы, которые обеспечивают некоторый контроль над его состоянием.

Мы можем добиться этого, определив методы deposit и withdraw для BankAccount. Таким образом, мы можем определить метод transfer_to, который использует только этот API.

class BankAccount:
    def __init__(self):
        self.balance = 0

    def deposit(self, amount):
        self.balance += amount

    def withdraw(self, amount):
        if amount >= self.balance:
            self.balance -= amount
        else:
            raise ValueError('Insufficient funds')

    def transfer_to(self, target, amount):
        if isinstance(target, BankAccount):
            self.withdraw(amount)
            target.deposit(amount)
        else:
            raise ValueError("'target' must be another BankAccount")

Преимущество

Инкапсулируя логику withdraw, deposit и tranfer_to, мы допускаем простую реализацию более сложных типов учетных записей посредством наследования.

Здесь приведем пример нового типа BankAccount, который учитывает отрицательный баланс.

class CreditAccount(BankAccount):
    def withdraw(self, amount):
        self._balance -= amount

Полностью делегируя ответственность за снятие средств с экземпляров BankAccount, мы позволяем внешним агентам манипулировать аккаунтом, не зная внутренней логики снятия и внесения.

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