• Post Reply Bookmark Topic Watch Topic
  • New Topic

Design suggestion  RSS feed

 
Mandy Ram
Greenhorn
Posts: 16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,
I need to design a simple banking app give the below data:

Account types : Savings and Checkings
Customer types: Normal and Priviliged

Interest rate for :

Savings Account for a Normal Customer is 10%
Savings Account for a Priviliged Customer is 15%

Checkings acccount for a Normal Customer is 8%
Checkings Account for a Priviliged Customer is 9%

I am trying to design the classes for the above requirement. While designing,I want to consider the below design principles

-> Program to interface or abstract class rather than concrete classs
-> Prefer Composition rather than Inheritance.

Based on the above principles and requirement, I am able to come up with the below design

Customer super abstract class and 2 concrete classes:




abstract super Account class and 2 concrete classes:



The below is the test class




I am getting the result but am not happy with the design for the following reasons:

1) The getInterestRate() in the SavingsAccount and checkingsAccount have referenced to concrete classes instead of interfaces or abstract classes.

this violates the deisgn principle - "Program to interfaces or abstract classes rather than concrete classes"

2) In future, if a new customer type is introduced, I have to change the logic in the getInterest() method in Savings account and CheckingsAccount classes

This violates the design principle that "Existing Java code/classes should be open for extension and closed for modification"

It would be good that, even if a new Customer type or a new Acccount type is introduced by the client, only new classes should be added instead of changing the existing clases.


Can some one please give me some pointers/suggestions for a neat design to this problem?

Thanks in advance.
 
Campbell Ritchie
Marshal
Posts: 56518
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Can you change an ordinary customer to a privileged one? If so, you should not have two classes. You can have some sort of marker in the Customer class about their status.
 
Mandy Ram
Greenhorn
Posts: 16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for your reply.

If I have marker in the Customer class, say a String variable "type",Even then getInterestRate() method will have hardcoded values like:



If a new customer type is added in fututre,I will end up changing the code in both SavingsAccount and CheckingsAccount classes.

Is there no approach to change the design incorporating some design patterns such that it looks neat and at the same time follows the design principles?

 
Campbell Ritchie
Marshal
Posts: 56518
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Not a String, no.
Try an enum.
 
Junilu Lacar
Sheriff
Posts: 11476
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The red flag is your use of instanceof - that's what causes you to break the open-closed principle. This means that something else other than the Account class should be responsible for "knowing" what the interest rate is. From your current logic though, it appears that the combination of Account and Customer is what determines the interest rate. The first data structure that comes to mind is a Map. An InterestTable object is what I might try. This class is responsible for knowing/calculating the interest rate given an Account and Customer.

If you go with this and you add a new customer or account type in the future, you would extend the InterestTable class, or simply "register" the new Customer, Account, and interest rates. Nothing else would need to change.
 
K. Tsang
Bartender
Posts: 3648
16
Firefox Browser Java Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The first thing I noticed is you have "a customer in an account". I would consider the other way round - a customer has an account.

For the account, I actually would use an interface rather than abstract class. Then have the CheckingAccount and SavingsAccount implement the getInterestRate() method.
 
Junilu Lacar
Sheriff
Posts: 11476
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
K. Tsang wrote:The first thing I noticed is you have "a customer in an account". I would consider the other way round - a customer has an account.

For the account, I actually would use an interface rather than abstract class. Then have the CheckingAccount and SavingsAccount implement the getInterestRate() method.


I don't see how any of these suggestions address the design issues that the OP asked about. How does reversing ownership roles help prevent violating the OCP if a new Customer or Account type is introduced?

While programming to interfaces is a fine approach in and of itself, in this case I don't see anything wrong with the choice of using an abstract class, at least not with the given code. The abstract class actually establishes that there is a relationship between an Account and Customer. If you were to start with an interface, you would have to establish the relationship some other way.
 
K. Tsang
Bartender
Posts: 3648
16
Firefox Browser Java Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:I don't see how any of these suggestions address the design issues that the OP asked about. How does reversing ownership roles help prevent violating the OCP if a new Customer or Account type is introduced?

While programming to interfaces is a fine approach in and of itself, in this case I don't see anything wrong with the choice of using an abstract class, at least not with the given code. The abstract class actually establishes that there is a relationship between an Account and Customer. If you were to start with an interface, you would have to establish the relationship some other way.


I'm not saying the OP approach is wrong nor am I saying my approach is better. Actually my approach may also violate OCP...

The relationship between Account and Customer is just a bit odd for me at first, depending on which way you look at it. Customer has Account or Account belongs to Customer... means the same thing.
 
Junilu Lacar
Sheriff
Posts: 11476
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
K. Tsang wrote:The relationship between Account and Customer is just a bit odd for me at first, depending on which way you look at it. Customer has Account or Account belongs to Customer... means the same thing.


I don't think it's uncommon. All it tells me is that an Account "knows" which customer is associated with it. The given code doesn't show it but it's not hard to imagine that a Customer should also "know" what Accounts it is associated with. If you had that kind of setup, then there's a two-way relationship, rather than one-way. If the Account didn't have any knowledge of which Customer it was associated with, then you'd have to go and query all Customer objects and see if they had that particular Account if the question of ownership ever came up.
 
Mandy Ram
Greenhorn
Posts: 16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:The red flag is your use of instanceof - that's what causes you to break the open-closed principle. This means that something else other than the Account class should be responsible for "knowing" what the interest rate is. From your current logic though, it appears that the combination of Account and Customer is what determines the interest rate. The first data structure that comes to mind is a Map. An InterestTable object is what I might try. This class is responsible for knowing/calculating the interest rate given an Account and Customer.

If you go with this and you add a new customer or account type in the future, you would extend the InterestTable class, or simply "register" the new Customer, Account, and interest rates. Nothing else would need to change.


Thanks for your reply. Can you please throw some light on your suggestion?

Are you saying I need another class (other than Account classes and Customer classes) which has a method taking customer and account objects as function augments and calculate the interest in that method?
This way , if a new account and customer type is introduced in future,the new class(service) class will be changed but not the Account and Customer classes.Do you mean the same?

What does the map contain? Are you saying we will initialize the map with the interest rates at the startup?Can you please eloborate your suggestion?




 
Mandy Ram
Greenhorn
Posts: 16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
K. Tsang wrote:The first thing I noticed is you have "a customer in an account". I would consider the other way round - a customer has an account.

For the account, I actually would use an interface rather than abstract class. Then have the CheckingAccount and SavingsAccount implement the getInterestRate() method.


Thanks for your reply.As Lacer mentioned, the reason for me having the account as abstract class instead of interface is because of the customer reference that I have in Account class.Also,i think it should be two way as Lacer suggested.Account has customer and customer has account.

I can make account as interface and remove customer reference from Account and have one abstract class implementing the interface and which has customer reference and can then make my Savings and CheckingsAccount classes extend that abstract class.That can be done.I am actually looking for other changes which can make the design better in terms of extensibility.

Thanks
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mandy Ram wrote:I can make account as interface and remove customer reference from Account and have one abstract class implementing the interface and which has customer reference and can then make my Savings and CheckingsAccount classes extend that abstract class.That can be done.

I have to admit a slight preference for that approach: ie:
interface defines behaviour (and type) → abstract class defines implementation common to all subclasses → subclasses define specific implementations
but, as Junilu said, there's nothing basically wrong with what you wrote.

I am actually looking for other changes which can make the design better in terms of extensibility.

Well, there is one thing that might be worth considering: an InterestRate class; because it's dependent on two things: Customer privilege and Account type. In information terms it's known as an 'associative entity' (sometimes called a cross-reference) because it's the result of a many-to-many relationship.

In Java terms a separate class might be overkill, since a method would probably suffice. It's also, arguably, more closely associated with an Account than it is with a Customer. But I think it's worth at least being aware of what it represents.

Winston
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!