1

I have the finance application where we can have different types of transactions, like balance enquiry, funds transfer, and pin change etc. Now the Transaction is a base class, and there are specific child classes implementing it as per above use cases.

Class Transaction
{
    int txnId;
    String sourceAccountNumber;
}
Class PinChange extends Transaction
{
    int pin;
}
Class FundsTransfer extends Transaction
{
    int amount;
    String destAccountNumber;
}

Now I have a BankService object which takes transaction and executes it.

Class BankService
{
    executeTransaction(Transaction transaction)
}

I want to know:

  1. How will BankService knows what is the type of transaction? Do I need to wrap it up in a new Enum like TransactionType and put it in transaction base class?

  2. When the BankService comes to know type of transaction, how will it access specific class details? I think it needs to type cast transaction to specific child class, which seems bad to me. Thoughts?

  • i dont see what is there to downvote.It is a design suggestion that i am trying to ask. – rahul sharma Dec 31 '20 at 13:54
  • A question for you: do you think that executeTransaction has a single responsibility? – Philip Kendall Dec 31 '20 at 13:58
  • Since it is performing multiple TYPES of transactions.So answer is No.Are you suggesting that i should expose API for each transaction,which makes sense to me but i thought I can use inheritance and run type polymorphism? – rahul sharma Dec 31 '20 at 14:05
  • Just because you can use inheritance does not mean that you should. – Philip Kendall Dec 31 '20 at 14:13
  • Why would you classify anything but money transfer as a transaction? – Martin Maat Jan 1 at 8:26
3

If you have execute() method overridden in each child class, you can just call transaction.execute() inside executeTransaction(), so BankService does not have to know the transaction type.

However, I don't see the necessity of using inheritance here --- you can just have fundsTransfer, pinChange,... methods inside BankService class and implement them separately:

Class BankService
{
    executeFundsTransfer(BankAccount source, BankAccount target, int amount);
    executePinChange(BankAccount source, int pin);
}

Update:

You can have TransactionType enum class and make it a member field in Transaction: DEPOSIT, and WITHDRAW, but I don't think pin update or other methods are transactions, and they don't have a common (single) responsibility in executeTransAction method, so yes enum work but I don't see a strong reason that you have to use that.

  • adding execute in transaction is not the ways i want to go.as it is just metadata and it does not know how to execute.Only bank knows how to execute it.So i would rather add separate api for each transaction – rahul sharma Dec 31 '20 at 14:45
  • @rahulsharma yeah that's what I was suggesting in the 2nd paragraph – lennon310 Dec 31 '20 at 15:46
  • is it bad to add ENUM named transactionType in transaction and then can read that enum and decide what to do? – rahul sharma Dec 31 '20 at 16:30
  • @rahulsharma updated the answer – lennon310 Dec 31 '20 at 16:42
5

You don't want BankService to know what the true type of the transaction parameter is.  It can find out by doing instanceof, but that is a red flag indicating OOP problems.

However, the transaction parameter variable knows what kind of object was passed in.

So, the idea is to tell the transaction object to do something for you, instead of inspecting it to see what to do.

The principle is called "Tell, don't Ask."

We don't have to use this approach, but using Ask instead of Tell is "contrary" to OOP.

  • so you are also suggesting to have separate api for each transaction,right?or what if I add an Enum with TransactionType in transaction object, and then the bank execute can see if what type of transaction is actually passed?Is it a suggested way? – rahul sharma Dec 31 '20 at 16:31
  • Ok, you want to use Ask not Tell. That's contrary to OOP but there's no OOP police or jail, so you can do that if you like. If you go that route, don't duplicate the type of transaction in an enum (assuming it is already explicit in hierarchy), just use instanceof. – Erik Eidt Dec 31 '20 at 16:36
  • this is first time i heard of this principle,tell not ask,I just read about it.Now i am confused that if I use ENUM,will i be violating it? it says we should not get state from object and then act on it.But to handle this thing we move everything to object, so it has only tell and not ask.Now let us say i tried to use ENUM and if it violate tell dont ask, then i should be able to handle this by moving asking logic to object class.but here for me it is not possible to move that logic to transaction class.I am not able to convince myself that using ENUM is actually a violation of tell dont ask? – rahul sharma Dec 31 '20 at 17:59
  • or may be i will not keep ENUM in trasaction object. I can keep transaction object as it is and then pass two parameters to execute(Transaction transaction, TransactionType type). In that way i will not be reading object state but something else sent along object.Just trying to know pro and con of different approaches? – rahul sharma Dec 31 '20 at 18:01
0

There have been some good answers, but I would like to add to them.

  1. Transaction is a terrible choice of base class name as it already has meaning, especially in financial and database-centric applications.
  2. Model the real world. When I front up to an ATM I know that I want to deposit, withdraw or transfer between accounts. I don't think along the lines "let's do a transaction - what type?". So rather than inheritance the service you call should reflect reallity and have separate entry points for each operation. This will aid maintenance in the future. But full marks for asking. Hopefully the community can help improve your design.
  • 1
    It does not strike me as odd to have a transaction class in a banking application, neither do I think the name is bad. Because performing transactions is core business to a bank. I do wonder why pin change or balance inquiry are considered transactions though. The point of a transaction is to make sure multiple steps are performed as one and this does not apply here. Anyway, the customer may not think in terms of transactions but what ultimately happens are transactions and this is the core logic. There will be a UI that caters to the user's model but that is not what we are talking about. – Martin Maat Jan 1 at 8:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.