Simple OOP currency converterSimple OOP currency converter - follow-upIntroductory Currency ConverterCurrency converter in PythonCurrency converter in Python 2.7Currency converter built with AngularJSSimple temperature converter in CCurrency Converter in Python 3Simple unit converter and shipment builderChangeCalculator for calculating money denominations in changeCurrency converter - CLI and APITemperature and currency converters in OOP JS
How are mathematicians paid to do research?
Do I have a right to cancel a purchase of foreign currency in the UK?
Should disabled buttons give feedback when clicked?
Why does wrapping aluminium foil around my food help it keep warm, even though aluminium is a good conductor?
What's the point of having a RAID 1 configuration over incremental backups to a secondary drive?
Is Trump personally blocking people on Twitter?
Astronaut distance from Earth?
Why didn't Thanos kill all the Dwarves on Nidavellir?
What specific instant in time in the MCU has been depicted the most times?
Does Multiverse exist in MCU?
Is English unusual in having no second person plural form?
Using `PlotLegends` with a `ColorFunction`
Can the Mage Hand cantrip be used to trip an enemy who is running away?
Salt, pepper, herbs and spices
How quality assurance engineers test calculations?
Print the last, middle and first character of your code
Graduate student with abysmal English writing skills, how to help
Why weren't bootable game disks ever common on the IBM PC?
Would a non-attacking Barbarian's rage end the same turn he started it?
Received a dinner invitation through my employer's email, is it ok to attend?
LED glows slightly during soldering
How to disable constructors in custom exceptions?
What is this little owl-like bird?
Would dual wielding daggers be a viable choice for a covert bodyguard?
Simple OOP currency converter
Simple OOP currency converter - follow-upIntroductory Currency ConverterCurrency converter in PythonCurrency converter in Python 2.7Currency converter built with AngularJSSimple temperature converter in CCurrency Converter in Python 3Simple unit converter and shipment builderChangeCalculator for calculating money denominations in changeCurrency converter - CLI and APITemperature and currency converters in OOP JS
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
I am learning about OOP so it would be great if you can give me feedback on how to improve my code and OOP design.
This is a currency converter. Firstly, it will call a method to add 2 currencies and commission information and then it converts to another currency whose input is source currency and amount:
import pytest
class Bank:
def addRate(self,first, second, rate):
self.first_currency = first
self.second_currency = second
self.rate = rate
def addCommission(self,commision):
self.commission = commision
def convert(self, currency, amount):
if currency == self.first_currency:
return (amount / self.rate) * (1-self.commission)
else:
return (amount * self.rate) * (1-self.commission)
@pytest.fixture()
def bank():
return Bank()
def test_Bank_addRate(bank):
bank.addRate("USD","GBP",2)
assert bank.first_currency == "USD"
assert bank.second_currency == "GBP"
assert bank.rate == 2
def test_Bank_addCommision(bank):
bank.addCommission(0.015)
assert bank.commission == 0.015
def test_Bank_convert(bank):
bank.addRate("USD", "GBP", 2)
bank.addCommission(0.015)
assert bank.convert("USD", 100) == 49.25
python beginner object-oriented unit-conversion
$endgroup$
|
show 3 more comments
$begingroup$
I am learning about OOP so it would be great if you can give me feedback on how to improve my code and OOP design.
This is a currency converter. Firstly, it will call a method to add 2 currencies and commission information and then it converts to another currency whose input is source currency and amount:
import pytest
class Bank:
def addRate(self,first, second, rate):
self.first_currency = first
self.second_currency = second
self.rate = rate
def addCommission(self,commision):
self.commission = commision
def convert(self, currency, amount):
if currency == self.first_currency:
return (amount / self.rate) * (1-self.commission)
else:
return (amount * self.rate) * (1-self.commission)
@pytest.fixture()
def bank():
return Bank()
def test_Bank_addRate(bank):
bank.addRate("USD","GBP",2)
assert bank.first_currency == "USD"
assert bank.second_currency == "GBP"
assert bank.rate == 2
def test_Bank_addCommision(bank):
bank.addCommission(0.015)
assert bank.commission == 0.015
def test_Bank_convert(bank):
bank.addRate("USD", "GBP", 2)
bank.addCommission(0.015)
assert bank.convert("USD", 100) == 49.25
python beginner object-oriented unit-conversion
$endgroup$
5
$begingroup$
Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
$endgroup$
– juhist
Jul 2 at 13:12
1
$begingroup$
Your code defines aCurrency
class but it doesn’t seem to be using it — what is its purpose?
$endgroup$
– Konrad Rudolph
Jul 2 at 13:14
$begingroup$
@KonradRudolph, thank you. I removed it
$endgroup$
– Nguyen
Jul 2 at 16:02
$begingroup$
@juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
$endgroup$
– Nguyen
Jul 2 at 16:04
2
$begingroup$
Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
$endgroup$
– Sᴀᴍ Onᴇᴌᴀ
Jul 2 at 16:08
|
show 3 more comments
$begingroup$
I am learning about OOP so it would be great if you can give me feedback on how to improve my code and OOP design.
This is a currency converter. Firstly, it will call a method to add 2 currencies and commission information and then it converts to another currency whose input is source currency and amount:
import pytest
class Bank:
def addRate(self,first, second, rate):
self.first_currency = first
self.second_currency = second
self.rate = rate
def addCommission(self,commision):
self.commission = commision
def convert(self, currency, amount):
if currency == self.first_currency:
return (amount / self.rate) * (1-self.commission)
else:
return (amount * self.rate) * (1-self.commission)
@pytest.fixture()
def bank():
return Bank()
def test_Bank_addRate(bank):
bank.addRate("USD","GBP",2)
assert bank.first_currency == "USD"
assert bank.second_currency == "GBP"
assert bank.rate == 2
def test_Bank_addCommision(bank):
bank.addCommission(0.015)
assert bank.commission == 0.015
def test_Bank_convert(bank):
bank.addRate("USD", "GBP", 2)
bank.addCommission(0.015)
assert bank.convert("USD", 100) == 49.25
python beginner object-oriented unit-conversion
$endgroup$
I am learning about OOP so it would be great if you can give me feedback on how to improve my code and OOP design.
This is a currency converter. Firstly, it will call a method to add 2 currencies and commission information and then it converts to another currency whose input is source currency and amount:
import pytest
class Bank:
def addRate(self,first, second, rate):
self.first_currency = first
self.second_currency = second
self.rate = rate
def addCommission(self,commision):
self.commission = commision
def convert(self, currency, amount):
if currency == self.first_currency:
return (amount / self.rate) * (1-self.commission)
else:
return (amount * self.rate) * (1-self.commission)
@pytest.fixture()
def bank():
return Bank()
def test_Bank_addRate(bank):
bank.addRate("USD","GBP",2)
assert bank.first_currency == "USD"
assert bank.second_currency == "GBP"
assert bank.rate == 2
def test_Bank_addCommision(bank):
bank.addCommission(0.015)
assert bank.commission == 0.015
def test_Bank_convert(bank):
bank.addRate("USD", "GBP", 2)
bank.addCommission(0.015)
assert bank.convert("USD", 100) == 49.25
python beginner object-oriented unit-conversion
python beginner object-oriented unit-conversion
edited Jul 2 at 16:01
Nguyen
asked Jul 2 at 1:31
NguyenNguyen
555 bronze badges
555 bronze badges
5
$begingroup$
Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
$endgroup$
– juhist
Jul 2 at 13:12
1
$begingroup$
Your code defines aCurrency
class but it doesn’t seem to be using it — what is its purpose?
$endgroup$
– Konrad Rudolph
Jul 2 at 13:14
$begingroup$
@KonradRudolph, thank you. I removed it
$endgroup$
– Nguyen
Jul 2 at 16:02
$begingroup$
@juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
$endgroup$
– Nguyen
Jul 2 at 16:04
2
$begingroup$
Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
$endgroup$
– Sᴀᴍ Onᴇᴌᴀ
Jul 2 at 16:08
|
show 3 more comments
5
$begingroup$
Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
$endgroup$
– juhist
Jul 2 at 13:12
1
$begingroup$
Your code defines aCurrency
class but it doesn’t seem to be using it — what is its purpose?
$endgroup$
– Konrad Rudolph
Jul 2 at 13:14
$begingroup$
@KonradRudolph, thank you. I removed it
$endgroup$
– Nguyen
Jul 2 at 16:02
$begingroup$
@juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
$endgroup$
– Nguyen
Jul 2 at 16:04
2
$begingroup$
Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
$endgroup$
– Sᴀᴍ Onᴇᴌᴀ
Jul 2 at 16:08
5
5
$begingroup$
Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
$endgroup$
– juhist
Jul 2 at 13:12
$begingroup$
Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
$endgroup$
– juhist
Jul 2 at 13:12
1
1
$begingroup$
Your code defines a
Currency
class but it doesn’t seem to be using it — what is its purpose?$endgroup$
– Konrad Rudolph
Jul 2 at 13:14
$begingroup$
Your code defines a
Currency
class but it doesn’t seem to be using it — what is its purpose?$endgroup$
– Konrad Rudolph
Jul 2 at 13:14
$begingroup$
@KonradRudolph, thank you. I removed it
$endgroup$
– Nguyen
Jul 2 at 16:02
$begingroup$
@KonradRudolph, thank you. I removed it
$endgroup$
– Nguyen
Jul 2 at 16:02
$begingroup$
@juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
$endgroup$
– Nguyen
Jul 2 at 16:04
$begingroup$
@juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
$endgroup$
– Nguyen
Jul 2 at 16:04
2
2
$begingroup$
Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
$endgroup$
– Sᴀᴍ Onᴇᴌᴀ
Jul 2 at 16:08
$begingroup$
Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
$endgroup$
– Sᴀᴍ Onᴇᴌᴀ
Jul 2 at 16:08
|
show 3 more comments
2 Answers
2
active
oldest
votes
$begingroup$
First: welcome to CodeReview! I hope that you get good feedback.
About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate()
can be called multiple times per single Bank
instance, and that convert
would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.
There are two ways to go, here. Either make your class an ExchangeRate, in which case
- you need to rename the class
convert
, rather than accepting the name of a currency, should perhaps accept aforward
boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e.dest_currency
.- Rename your addCommission to setCommission. "add" implies having more than one.
- Rename your addRate to setRate. "add" implies having more than one.
Or, keep a "Bank" class, in which case:
- you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member
- convert would accept both a source and destination currency
- addRate's signature would stay the same, but its contents would change to use your dict.
$endgroup$
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
add a comment |
$begingroup$
There are a few smells in your code.
Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.
What if you want to do GBP->EUR? do you create another bank?
- In real life, currency exchange rates change over time. How will your bank object reflect that?
- Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.
- Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.
A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.
$endgroup$
$begingroup$
Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
$endgroup$
– Nguyen
Jul 3 at 0:17
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
$begingroup$
4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
$endgroup$
– wallenborn
Jul 3 at 14:50
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f223322%2fsimple-oop-currency-converter%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
First: welcome to CodeReview! I hope that you get good feedback.
About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate()
can be called multiple times per single Bank
instance, and that convert
would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.
There are two ways to go, here. Either make your class an ExchangeRate, in which case
- you need to rename the class
convert
, rather than accepting the name of a currency, should perhaps accept aforward
boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e.dest_currency
.- Rename your addCommission to setCommission. "add" implies having more than one.
- Rename your addRate to setRate. "add" implies having more than one.
Or, keep a "Bank" class, in which case:
- you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member
- convert would accept both a source and destination currency
- addRate's signature would stay the same, but its contents would change to use your dict.
$endgroup$
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
add a comment |
$begingroup$
First: welcome to CodeReview! I hope that you get good feedback.
About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate()
can be called multiple times per single Bank
instance, and that convert
would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.
There are two ways to go, here. Either make your class an ExchangeRate, in which case
- you need to rename the class
convert
, rather than accepting the name of a currency, should perhaps accept aforward
boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e.dest_currency
.- Rename your addCommission to setCommission. "add" implies having more than one.
- Rename your addRate to setRate. "add" implies having more than one.
Or, keep a "Bank" class, in which case:
- you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member
- convert would accept both a source and destination currency
- addRate's signature would stay the same, but its contents would change to use your dict.
$endgroup$
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
add a comment |
$begingroup$
First: welcome to CodeReview! I hope that you get good feedback.
About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate()
can be called multiple times per single Bank
instance, and that convert
would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.
There are two ways to go, here. Either make your class an ExchangeRate, in which case
- you need to rename the class
convert
, rather than accepting the name of a currency, should perhaps accept aforward
boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e.dest_currency
.- Rename your addCommission to setCommission. "add" implies having more than one.
- Rename your addRate to setRate. "add" implies having more than one.
Or, keep a "Bank" class, in which case:
- you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member
- convert would accept both a source and destination currency
- addRate's signature would stay the same, but its contents would change to use your dict.
$endgroup$
First: welcome to CodeReview! I hope that you get good feedback.
About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate()
can be called multiple times per single Bank
instance, and that convert
would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.
There are two ways to go, here. Either make your class an ExchangeRate, in which case
- you need to rename the class
convert
, rather than accepting the name of a currency, should perhaps accept aforward
boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e.dest_currency
.- Rename your addCommission to setCommission. "add" implies having more than one.
- Rename your addRate to setRate. "add" implies having more than one.
Or, keep a "Bank" class, in which case:
- you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member
- convert would accept both a source and destination currency
- addRate's signature would stay the same, but its contents would change to use your dict.
answered Jul 2 at 2:44
ReinderienReinderien
6,16610 silver badges29 bronze badges
6,16610 silver badges29 bronze badges
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
add a comment |
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
add a comment |
$begingroup$
There are a few smells in your code.
Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.
What if you want to do GBP->EUR? do you create another bank?
- In real life, currency exchange rates change over time. How will your bank object reflect that?
- Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.
- Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.
A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.
$endgroup$
$begingroup$
Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
$endgroup$
– Nguyen
Jul 3 at 0:17
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
$begingroup$
4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
$endgroup$
– wallenborn
Jul 3 at 14:50
add a comment |
$begingroup$
There are a few smells in your code.
Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.
What if you want to do GBP->EUR? do you create another bank?
- In real life, currency exchange rates change over time. How will your bank object reflect that?
- Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.
- Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.
A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.
$endgroup$
$begingroup$
Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
$endgroup$
– Nguyen
Jul 3 at 0:17
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
$begingroup$
4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
$endgroup$
– wallenborn
Jul 3 at 14:50
add a comment |
$begingroup$
There are a few smells in your code.
Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.
What if you want to do GBP->EUR? do you create another bank?
- In real life, currency exchange rates change over time. How will your bank object reflect that?
- Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.
- Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.
A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.
$endgroup$
There are a few smells in your code.
Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.
What if you want to do GBP->EUR? do you create another bank?
- In real life, currency exchange rates change over time. How will your bank object reflect that?
- Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.
- Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.
A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.
answered Jul 2 at 16:29
wallenbornwallenborn
2911 silver badge4 bronze badges
2911 silver badge4 bronze badges
$begingroup$
Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
$endgroup$
– Nguyen
Jul 3 at 0:17
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
$begingroup$
4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
$endgroup$
– wallenborn
Jul 3 at 14:50
add a comment |
$begingroup$
Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
$endgroup$
– Nguyen
Jul 3 at 0:17
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
$begingroup$
4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
$endgroup$
– wallenborn
Jul 3 at 14:50
$begingroup$
Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
$endgroup$
– Nguyen
Jul 3 at 0:17
$begingroup$
Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
$endgroup$
– Nguyen
Jul 3 at 0:17
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19
$begingroup$
4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
$endgroup$
– wallenborn
Jul 3 at 14:50
$begingroup$
4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
$endgroup$
– wallenborn
Jul 3 at 14:50
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f223322%2fsimple-oop-currency-converter%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
5
$begingroup$
Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
$endgroup$
– juhist
Jul 2 at 13:12
1
$begingroup$
Your code defines a
Currency
class but it doesn’t seem to be using it — what is its purpose?$endgroup$
– Konrad Rudolph
Jul 2 at 13:14
$begingroup$
@KonradRudolph, thank you. I removed it
$endgroup$
– Nguyen
Jul 2 at 16:02
$begingroup$
@juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
$endgroup$
– Nguyen
Jul 2 at 16:04
2
$begingroup$
Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
$endgroup$
– Sᴀᴍ Onᴇᴌᴀ
Jul 2 at 16:08