As we move forward in a project, lost in if-else blocks, struggling with complex conditions and repetitive code, we look for a solution. But why sh...
Some comments have been hidden by the post's author - find out more
For further actions, you may consider blocking this person and/or reporting abuse
Great article but the title is a bit of an over-statement....
It sounds like if-else statements are a terrible thing...
This is not a silver bullet and for newbies reading this, don't go refactoring all your if-else blocks with this...
Understanding and mastering Design Patterns is a skill every developer needs to learn but most importantly, knowing when to use the right tool for the right job.
Sometimes, a simple if-else statement is the best solution... Know when to refactor
As this is Java, we could be using Java 21's pattern matching with sealed classes.
Current setup does not yield an error if a new type is given at build time, but with sealed classes it would.
I do like this Strategy pattern, but most times with an isActive or whatever how we call method that decides if we have to launch an implementation or not, that is great of multiple impls must be executed in chain.
I know this pattern under the name of branchless programming - the factory pattern is usually an OOP pattern where you define objects through methods, ie.
new MyProduct().color(Colors.Blue).size(Size.XL).build()
.That sounds like a version of the builder pattern to me, might be mistaken tho.
That is a builder pattern
Your
PaymentFactory
class isn't a factory. In the factory pattern, a factory method instantiates new object instances. In your example, thegetPaymentStrategy
method returns one of three pre-existing objects depending on payment type. Call that method again with same payment type and you get same payment strategy instance. This isn't a factory.I like this pattern, much more concise.
I would like to suggest a little improvement: I would use a switch Statement on the payment type instead of the map inside the PaymentFactory. Then you just get a compile error because a case is missing here if you happen to add another payment type. The map will fail at runtime :)
Reads the comments
Please don't take them to heart! I've done this for when code becomes really unmanageable and it's great stuff! Sometimes what we're missing is implementing patterns in practice to understand their usefulness.
Thanks for the article!
Thank you so much for your comment
Your titel is too much click bait for me. There is nothing wrong with IfThenElse. Any programming construct will probably be confusing if used in the wrong situation. But this is more of a problem with the programmer than with the method.
Look at this example.
Please show me how this could be made simpler with the factory pattern?
You can simplify this with ternary operator like this:
But this will be harder to read, as the ternary operator is meant to be used in a different way like this and in this case it will be better readable:
There have been multiple posts about escaping the if/else hell like here, but it depends much on your task which one fit´s best.
If you need a "default"-case, you can use this:
Another pattern I like much is this a special form to use the ternary operator:
Thank you very much for your comment. I think you missed the point a little bit. I did this to keep it a bit simple, but either your or my examples do not represent the real-world situation.
For example, no one logs if the payment type is a credit card. In the real world, we do some service calling, then insert or update data in the database, and finally respond to an API call.
In this scenario, every if-else block has too many code lines. This is very messy and contrary to SOLID principles. And I've seen people doing extremely complex jobs using too much if-else, which makes it very difficult for newcomers to understand the code.
Of course, if you are a beginner or actions are simple, you can use if-else blocks. I also use if-else blocks to do simple checks. Not using them for simple operations would be overengineering.
And I admit the title is a bit click-bait...
In summary, this article was not for beginners, but for those who are already working on a large project and using if-else or switch-case in complex operations.
By doing so, if another method is added in the future, we comply with the Open-Closed Principle by creating new classes without touching the existing code, rather than adding a new else if in the service.
I hope I have explained who this article is more suitable for.
Dont use cars anymore, I invented a rocket...
I know things can get very messy and it is good to know solutions for that. But this is a very special solution to a very special problem and I suppose, there are many ways to solve this in a structured manner. If you tried to use If/else for that, it shows just your limited experience, it has nothing to do with limitations of the if/else construction.
Maybe you sould be a bit more careful with your titles...
I would never replace something so simple as if-else with more abstraction and patterns.
The only thing I would do is to use "switch expressions" and that's it.
this is "merchant of complexity" category
I recall reading something similar to this on CodeProject 15 years ago. Was interested then but never implemented it. Today I find it rare to have huge if then or switch statements. Thanks for reminding me....
Just a heads up that you can add highlighting to the code blocks if you'd like. Just change:
... to specify the language:
More details in our editor guide!
Wow thanks, I didn't know that
I wouldn't say never use if/else. What if inside credit card payments you have chip, tap, swipe, Google Pay, Apple Pay.
Now we have ChipCardPayment, TapCardPayment, SwipeCardPayment, GooglePayCardPayment, ApplePayCardPayment.
If you don't use if/else your're stuck creating a class for every condition. What about non oop languages, they won't be able to fully follow this principle.
This is a good solution when the if else chain is known to be open ended. You should consider populating the factory from a configuration element so that no code is needed to add elements. This also opens the door to disable forms of payment and track there usage via configuration as well. Thanks for sharing!
Hello Tamer, thank you for the appreciated tutorial.
I'd need to say more people judge about article without knowledge. some people see if else best and some see more classes wil be created.
You guys should read more about SOLID principles because most of all design patterns are based on them.
Also solid and design pattern benefits won't appear with small business, always appear with big projectsand big business when you need to apply clean Architecture for your project.
We always face big problems with switch cases and else if in projects and in finally we replace it with strategy DP.
Read more and learn more, I believe DP is the best practice to make your code clean, readable, and maintainable.
Thank you all.
@tamerardal Nice article! Its very pin to the point and great explanation too.
I tried similar article, with little advanced by adding selection of
card(bankcard1, bankcard2..etc),
UPI (upi1,upi2... etc),
online banking (online banking1, onlinebanking2.. etc)
Have a look and add your thoughts and suggestions
Mastering Multiple Payment Gateways with Strategy and Abstract factory Combo
btw, you are still using
if
in the PaymentService, also strategy.get probably uses 'if'PaymentFactory
is not following the factory pattern. Factory pattern creates new objects. What you have is just a collection ofPaymentStrategy
implementations. Using the strategy pattern is great, but really falls short on the factory. Solving the for theif...else
I would of just done aswitch
statement calling the correctPaymentStrategy
Implementation. Deleting thePaymentFactory
class.I like the enum approach. Ofen I let the enum implement the interface directly.
You can use the below syntax to enable syntax highlighting in Dev.to
triplebacktick java
code
triplebacktick
Great article, thanks!
I think you need to find a spesific use case for such a pattern, don't start refactoring all of your if/else's..
Great article. Clearly explained how we can make use of these concepts. Appreciate it.
Thanks 🙂
Sometimes I'm asking myself if we're trying too much:
13 lines
of code, all collocated in1
file48 lines
of code and you need 4 different files, most likely in different foldersAs with any pattern, there's a time for using it and a time not to. I feel the trade-off is not worth it in this particular example. I'm not saying the pattern is bad, I'm simply pointing out the example here is very bad to drive your point.
Yes, because the original example is example. Doesn't have any business logic. If you add all payment logic, it will be so complicated. Think like that. And it's not all about shortening the line of code. Long but maintainable is more important.
If you use a lot of if-else in your project and you need it like this, use it. If you are already doing simple operations, you do not need to use it. There is no point in counting the lines of code in this example because this is an example I simplified to explain.
Great article!
Extensibility: A false goal. In practice code is written to accomplish a business function and can't be extended in such a simplistic manner. The requirements change sufficiently it's a redesign. If you extend a program a pub/sub model is far superior. You don't have to change code handling existing functionality at all.
Readability: I can right click on a function call in an if statement and choose 'show definition'. Tracking down an implementation through a factory patter is much harder.
Maintainability: See previous points.
To be fair what I see is that you have replaced 8 simple lines of code with lots of code that doesn't do a thing. This is the opposite of "improves the readability" and the opposite of "more developable". Strategy pattern is overkill in most cases except for rare ones and you didn't provide good examples where strategy pattern would be a good fit except for one example where it's overkill and makes everything more complicated without a reason.
Be careful, it might sound good and your ego might get a boost, when no one is understanding you. The code will get thrown out, if the next person do not understand it. You might say, that the guy is a bad programmer, it does not matter, all your work goes down the drain, it will be re-written. Very basic programming fact, keep it simple, otherwise, you yourself will not understand it after a while.
You can use a switch statement instead of a long if then else statement.
I will be very careful about the person who says "Don't use if-else blocks anymore"
Good luck.
These are good for publishing papers.
Based on your example, I'll go with if-else. Simpler and cleaner. You can refactor it once it becomes bigger.
Really? You created a bunch of subclasses just for this? So can you now explain what "strategies.get(paymentType);" is doing that is not an if else?
This works, but it seems to repeat the same code to get payment every time. Isn't there a better way to do this?
note: I am learning Python, so there are definitely some differences...
Is this only for Java ?
Of course is not. You can use it in every OOP Language.
Any Turing complete language may implement the same.
But exact details, will it be that directly apparent or not - will differ.
Have you done any profiling on speed one method vs the other? Do you think this could be an issue when it comes to software that depends on high-speed transactions?
I wrote almost this code a few years ago.