HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Design for a Java Banking program

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
designprogramjavabankingfor

Problem

UPDATE: Added concise problem summary and sample output log.

I tried coding a sample Java program to solve a problem statement:

  • Java Banking Demo Problem statement



  • Complete code for Java Banking Demo



Concise Problem summary:


Design and Implement an Engine that processes the SMS messages which
are sent from a users device (mobile). The messages will come to
engine as plain text data.


The message contains instructions to



  • Process a banking transaction



  • Modify a users profile





Based on messages mentioned above, the messages can be of two types:



  • Transaction request that makes changes to the account



  • Request to modify user profile





The operation corresponding to each type of message can have a pre and
post step and the actual operation step.


Important



  • Assume each user has a fixed. pre-defined and unique





Mobile Number Authentication PIN Transaction PIN Email Id


Populate this information in an in memory data structure / file system
which can be used for authentication. Authentication of PIN will
involve just validating the mobiie number against PIN numbers and
making sure they are same as expected values.

Sample output log

Enter the no of records:
1
Enter the record no:1
anurag|anurag@gmail.com|8105720566|7|2708|2708
Record written to the transaction file: anurag|anurag@gmail.com|8105720566|7|2708|2708
Enter the no of transactions:
1
Enter the transaction no:1
mo|7|7|200|2708|2708|anurag@eanurag.com
User found in the transaction file: anurag|anurag@gmail.com|8105720566|7|2708|2708
8105720566:PIN authenticated
User found in the transaction file: anurag|anurag@gmail.com|8105720566|7|2708|2708
Record written to the transaction file: anurag|anurag@eanurag.com|8105720566|7|2708|2708
8105720566:Update completed for mo|7|7|200|2708|2708|anurag@eanurag.com


User:

```
package com.banking.businessobject;

import java.math.BigInteger;
import java.util.Objects;

public c

Solution

TransactionImpl#accountAuthentication

I'll start with accountAuthentication method from TransactionImpl:

@Override
public boolean accountAuthentication(User user, Transaction trnObj) {
    boolean authentication = false;
    IFileIO fi = new FileIO();
    User userRecord = fi.readTransactionFile(user);
    if (userRecord.getMobileNumber().intValue() == user.getMobileNumber()
            .intValue()
            && userRecord.getAccount().getAuthPin().intValue() == user
            .getAccount().getAuthPin().intValue()) {
        if (trnObj.getTransactionType().toLowerCase().equals("tx")
                && trnObj.getTransactionAmount().intValue() > 1000) {
            if (userRecord.getAccount().getTransactionPin().intValue() != user
                    .getAccount().getTransactionPin().intValue()) {
                return authentication;
            }
        }

        authentication = true;
    }
    return authentication;
}


You can extract the big if in a separate method:

@Override
public boolean accountAuthentication(User user, Transaction trnObj) {
    boolean authentication = false;
    IFileIO fi = new FileIO();
    User userRecord = fi.readTransactionFile(user);
    if (isBadAuthentication(user, trnObj, userRecord)) {
        return authentication;
    }
    authentication = true;

    return authentication;
}


Then we can get rid of authentication temp variable:

public boolean accountAuthentication2(User user, Transaction trnObj) {
    IFileIO fi = new FileIO();
    User userRecord = fi.readTransactionFile(user);
    return verifyAuthentication(user, trnObj, userRecord);
}


Now for the verifyAuthentication method, I extracted each condition in a separate method
and inverted the negative conditions. If we need to check for a negative, we can use !.

private boolean verifyAuthentication(User user, Transaction trnObj, User userRecord) {
    return verifyMobilePhone(user, userRecord) &&
           verifyAuthPin(user, userRecord) &&
           !isTxTransaction(trnObj) &&
           !hasBigAmount(trnObj) &&
           verifyTransactionPin(user, userRecord);
}

private boolean verifyTransactionPin(User user, User userRecord) {
    return userRecord.getAccount().getTransactionPin().intValue() ==
           user.getAccount().getTransactionPin().intValue();
 }

private boolean hasBigAmount(Transaction trnObj) {
    return trnObj.getTransactionAmount().intValue() > 1000;
}

private boolean isTxTransaction(Transaction trnObj) {
    return trnObj.getTransactionType().toLowerCase().equals("tx");
}

private boolean verifyAuthPin(User user, User userRecord) {
    return userRecord.getAccount().getAuthPin().intValue() ==
           user.getAccount().getAuthPin().intValue();
}

private boolean verifyMobilePhone(User user, User userRecord) {
    return userRecord.getMobileNumber().intValue() ==
           user.getMobileNumber().intValue();
}


We have many small methods now, but we can easily move them to their related class.
For example, we move isTxTransaction and hasBigAmount right in the Transaction class:

Transaction.java :

public boolean isTx() {
    return getTransactionType().toLowerCase().equals("tx");
}

public boolean hasBigAmount() {
    return getTransactionAmount().intValue() > 1000;
}


TransactionImpl.java :

private boolean verifyAuthentication(User user, Transaction trnObj, User userRecord) {
    return verifyMobilePhone(user, userRecord) &&
           verifyAuthPin(user, userRecord) &&
           !trnObj.isTx() &&
           !trnObj.hasBigAmount() &&
           verifyTransactionPin(user, userRecord);
}


Integers are automatically unboxed, there is no need to call intValue in hasBigAmount:

public boolean hasBigAmount() {
    return getTransactionAmount() > 1000;
}


SmsGatewayImpl#receiveNextMessage

receiveNextMessage has this big switch:

```
switch (trnObj.getTransactionType().toLowerCase()) {
case "tx":
authPinNotification = notifyPinAuthenticationResult(user, authenticated);
if (!authPinNotification.isEmpty() && authPinNotification != null) {
System.out.println(authPinNotification);
}
if (trnObj.getTransactionAmount() > 1000) {
transPinNotification = notifyTransPinAuthenticationResult(user, authenticated);

if (!transPinNotification.isEmpty() && transPinNotification != null) {
System.out.println(transPinNotification);
}
}
transactionNotification = notifyTransactionResult(user, trnObj, authenticated);
if (!transactionNotification.isEmpty() && transactionNotification != null) {
System.out.println(transactionNotification);
}
break;

case "mo":
authPinNotification = notifyPinAuthenticationResult(user, authenticated);
if (!authPinNotification.isEmpty() && authPinNotification != null) {
System.out.println(authPinNotification);
}

Code Snippets

@Override
public boolean accountAuthentication(User user, Transaction trnObj) {
    boolean authentication = false;
    IFileIO fi = new FileIO();
    User userRecord = fi.readTransactionFile(user);
    if (userRecord.getMobileNumber().intValue() == user.getMobileNumber()
            .intValue()
            && userRecord.getAccount().getAuthPin().intValue() == user
            .getAccount().getAuthPin().intValue()) {
        if (trnObj.getTransactionType().toLowerCase().equals("tx")
                && trnObj.getTransactionAmount().intValue() > 1000) {
            if (userRecord.getAccount().getTransactionPin().intValue() != user
                    .getAccount().getTransactionPin().intValue()) {
                return authentication;
            }
        }

        authentication = true;
    }
    return authentication;
}
@Override
public boolean accountAuthentication(User user, Transaction trnObj) {
    boolean authentication = false;
    IFileIO fi = new FileIO();
    User userRecord = fi.readTransactionFile(user);
    if (isBadAuthentication(user, trnObj, userRecord)) {
        return authentication;
    }
    authentication = true;

    return authentication;
}
public boolean accountAuthentication2(User user, Transaction trnObj) {
    IFileIO fi = new FileIO();
    User userRecord = fi.readTransactionFile(user);
    return verifyAuthentication(user, trnObj, userRecord);
}
private boolean verifyAuthentication(User user, Transaction trnObj, User userRecord) {
    return verifyMobilePhone(user, userRecord) &&
           verifyAuthPin(user, userRecord) &&
           !isTxTransaction(trnObj) &&
           !hasBigAmount(trnObj) &&
           verifyTransactionPin(user, userRecord);
}

private boolean verifyTransactionPin(User user, User userRecord) {
    return userRecord.getAccount().getTransactionPin().intValue() ==
           user.getAccount().getTransactionPin().intValue();
 }

private boolean hasBigAmount(Transaction trnObj) {
    return trnObj.getTransactionAmount().intValue() > 1000;
}

private boolean isTxTransaction(Transaction trnObj) {
    return trnObj.getTransactionType().toLowerCase().equals("tx");
}

private boolean verifyAuthPin(User user, User userRecord) {
    return userRecord.getAccount().getAuthPin().intValue() ==
           user.getAccount().getAuthPin().intValue();
}

private boolean verifyMobilePhone(User user, User userRecord) {
    return userRecord.getMobileNumber().intValue() ==
           user.getMobileNumber().intValue();
}
public boolean isTx() {
    return getTransactionType().toLowerCase().equals("tx");
}

public boolean hasBigAmount() {
    return getTransactionAmount().intValue() > 1000;
}

Context

StackExchange Code Review Q#114493, answer score: 4

Revisions (0)

No revisions yet.