patterncppMinor
Clean code attempt at ATM problem on codechef.com
Viewed 0 times
problemcodechefattemptcodecomatmclean
Problem
The problem asks you to take an integer (debit amount) and a double (credit or initial balance amount) and process the requested debit verifying that 1 it's a multiple of the minimum denomimation amount of $5 and that it's also smaller than the credit/balance. If either is untrue, it is supposed to return the initial deposit amount otherwise it will return the new balance.
Full problem description
I have created 3 objects for this problem:
Limitations:
I understand that it can only process a single account, but that is more a limitation set by the problem description than it is me not accounting for multiple accounts. Also no error is returned if the balance cannot be updated, but it is not a requirement. I also understand I made a mountain out of a molehill with this problem as it can be solved by much less code.
In what ways can I improve this code other than the limitations mentioned?
```
#include
#include
#include
class Account {
public:
Account()
: mBalance(0.0)
{}
void updateBalance(double transaction) {
mBalance += transaction;
}
double getBalance() {
return mBalance;
}
private:
double mBalance;
};
class Transaction {
public:
Transaction()
: mDebit(0)
, mCredit(0.0)
{}
int getDebit() {
return mDebit;
}
double getCredit() {
return mCredit;
}
friend std::istream& operator>>(std::istream& input, Transaction& transaction) {
input >> transaction.mDebit;
input >> transaction.mCredit;
return input;
}
private:
int mDebit;
double mCredit;
};
class ATM {
public:
ATM()
Full problem description
I have created 3 objects for this problem:
Transaction- This object reads in the two initial values given and then is used in ATM
ATM- Takes the transaction and applies them to the account and then displays the new balance.
Account- This object keeps track of the current account balance and updates the balance if the ATM passes it a value.
Limitations:
I understand that it can only process a single account, but that is more a limitation set by the problem description than it is me not accounting for multiple accounts. Also no error is returned if the balance cannot be updated, but it is not a requirement. I also understand I made a mountain out of a molehill with this problem as it can be solved by much less code.
In what ways can I improve this code other than the limitations mentioned?
```
#include
#include
#include
class Account {
public:
Account()
: mBalance(0.0)
{}
void updateBalance(double transaction) {
mBalance += transaction;
}
double getBalance() {
return mBalance;
}
private:
double mBalance;
};
class Transaction {
public:
Transaction()
: mDebit(0)
, mCredit(0.0)
{}
int getDebit() {
return mDebit;
}
double getCredit() {
return mCredit;
}
friend std::istream& operator>>(std::istream& input, Transaction& transaction) {
input >> transaction.mDebit;
input >> transaction.mCredit;
return input;
}
private:
int mDebit;
double mCredit;
};
class ATM {
public:
ATM()
Solution
This looks quite readable and easy to follow. I just have a few things that have stuck out to me:
-
It would not be good to use a floating-point type for currency, and it's especially worse for a more accurate type like a
Refer to this, this and this for more info. There are already many resources on this very topic.
-
Your "getters" should be
Moreover, consider redesigning this to avoid getters. They (and also setters) are generally bad for encapsulation as they expose implementation details. You may not even need them here, either.
-
You can replace
-
It would not be good to use a floating-point type for currency, and it's especially worse for a more accurate type like a
double. For instance, you can wind up with a value like 0.0001, which is not an ideal value to deal with. Unfortunately, C++ doesn't have a standard library to deal with this, such as Java's BigDecimal. You need an integer type for this, which avoids these problems.Refer to this, this and this for more info. There are already many resources on this very topic.
-
Your "getters" should be
const as they're not supposed to modify data members:int getSomeMember() const {
return someMember;
}mMinDenominations should also be const for the same reason. Initializer lists do also allow initialization of const members (be aware that constructors cannot do this).Moreover, consider redesigning this to avoid getters. They (and also setters) are generally bad for encapsulation as they expose implementation details. You may not even need them here, either.
-
You can replace
displayBalance() with an overload of `operatorCode Snippets
int getSomeMember() const {
return someMember;
}friend std::ostream& operator<<(std::ostream& out, ATM const& obj) {
return out << obj.mAccount.getBalance() << '\n';
}Context
StackExchange Code Review Q#60379, answer score: 7
Revisions (0)
No revisions yet.