Как правильно осуществить взаимодействие между абстрактным и наследуемыми классами в JAVA?
Всем добрый день! Столкнулся с проблемой при решении задачи, суть которой в осуществлении правильного взаимодействия между классами: запутался в прописании методов. Прошу Вашей помощи! Вот условия задачи: Создаю абстрактный класс Account с тремя методами. Добавляю классы Сберегательный, Кредитный, Расчетный (SavingsAccount, CreditAccount, CheckingAccount соответственно) как потомков класса Счет. В них переопределяю методы. Каждый из них должен хранить баланс. Со сберегательного счета нельзя платить, только переводить и пополнять. Также сберегательный не может уходить в минус. Кредитный не может иметь положительный баланс – если платить с него, то уходит в минус, чтобы вернуть в 0, надо пополнить его. Расчетный может выполнять все три операции, но не может уходить в минус. Нужно продемонстрировать работу счетов. Также создать три переменные типа Account и присвоить им три разных типа счетов. Большинство методов оставил незаполненными. Вот мой код:
public abstract class Account {
protected int amount;
protected int balance;
public Account(int amount, int balance) {
this.amount = amount;
this.balance = balance;
}
void pay(int amount) { }
void transfer(Account account, int amount) { }
void addMoney(int amount) { }
}
public class SavingsAccount extends Account {
public SavingsAccount(int amount, int balance) {
super(amount, balance);
}
@Override
void pay(int amount) {
super.pay(amount);
}
@Override
void transfer(Account account, int amount) {
if (balance -= amount) {
System.out.println("Баланс не может быть отрицательным!");
}
}
@Override
void addMoney(int amount) {
super.addMoney(amount);
}
}
public class CreditAccount extends Account {
public CreditAccount(int amount, int balance) {
super(amount, balance);
}
@Override
void pay(int amount) {
super.pay(amount);
}
@Override
void transfer(Account account, int amount) {
super.transfer(account, amount);
}
@Override
void addMoney(int amount) {
super.addMoney(amount);
}
}
public class CheckingAccount extends Account {
public CheckingAccount(int amount, int balance) {
super(amount, balance);
}
@Override
void pay(int amount) {
super.pay(amount);
}
@Override
void transfer(Account account, int amount) {
super.transfer(account, amount);
}
@Override
void addMoney(int amount) {
super.addMoney(amount);
}
}
Ответы (2 шт):
Начнем с того, что если у вас есть какой-то счет с которого нельзя что-то делать, то это явный признак того, что их нужно разбить.
Ну конечно можно к примеру в вашем сберегательном счете переопределить метод pay() который будет бросать Exception или что-то вроде того, но это очень плохая практика. Вы можете создать родительский класс вроде такого:
public abstract class Account {
protected int balance;
public Account(int balance) {
this.balance = balance;
}
abstract void transfer(Account account, int amount);
abstract void addMoney(int amount);
}
Если базовый класс не задает никакого общего поведения для наследников, то методы лучше сделать абстрактными.
И интерфейс:
interface Payment {
void pay(int amount);
}
В каждом из наследников переопределить методы, например так:
public class CreditAccount extends Account implements Payment {
public CreditAccount(int balance) {
super(balance);
}
@Override
void pay(int amount) {
balance = balance - amount; // возможно тут более сложная логика может быть
}
@Override
void transfer(Account account, int amount) {
account.addMoney(amount);
balance = balance - amount; // тут может быть какая-то логика по обработке лимитов кредитки
}
@Override
void addMoney(int amount) {
if(balance + amount > 0) {
// обработать ситуацию когда больше пополнять нельзя. Может быть вернуть остаток или запретить операцию
} else {
balance = balance + amount
}
}
}
...
public class SavingsAccount extends Account {
public SavingsAccount(int balance) {
super(balance);
}
@Override
void transfer(Account account, int amount) {
account.addMoney(amount);
if (balance < amount) {
// обработать ошибку - недостаточно средств
} else {
balance = balance - amount; // тут может быть какая-то логика по обработке лимитов кредитки
}
}
@Override
void addMoney(int amount) {
balance = balance + amount
}
}
Это в общих чертах, но выглядеть должно примерно так. Конечно можно вместо интерфейса сделать еще один абстрактный класс который будет наследоваться от Account и в нем будет метод pay() назвать его к примеру PaymentAccount. И сберегательный счет будет наследоваться от Account а кредитный и расчетный будут от PaymentAccount, но если в этом нет необходимости то всегда стоит предпочитать интерфейсы абстрактным классам.
P.S. Я не совсем понял в чем разница полей amount и balance, поэтому оставил только одно. Но от этого суть не меняется.
Я бы сделал по другому. Попробуйте так
public abstract class Account {
private int amount;
private int balance;
public Account(int amount, int balance) {
this.amount = amount;
this.balance = balance;
}
public int getAmount() { return this.amount;}
void setAmount(int amount) { this.amount = amount;}
// getter setter для баланса
}
// реализуйте интерфейсы Pay,Transfer, Add для каждого класса
public class SavingsAccount extends Account implements Pay,Transfer, Add {
}
public class CheckingAccount extends Account implements Pay,Transfer, Add {
}
public class CreditAccount extends Account implements Pay,Transfer, Add {
}
Реализуйте только нужные интерфейсы для ваших классов и почитайте принципы SOLID. Почитайте повнимательней принцип постановки Liskov. Почитав его вы поймете что не надо плодить классы если нет в них необходимости.