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.Great article! Your explanation of how to replace if-else blocks with the Strategy and Factory patterns is clear and practical. The use of enums and EnumMap for organizing payment strategies is a clever approach that enhances both maintainability and readability. It's a perfect example of applying design patterns to create a more scalable solution in software development. I'm definitely inspired to implement this in my own projects!
Suggestion:
Consider adding a section that discusses potential pitfalls or challenges when implementing these patterns. For instance, it could be helpful to address how to manage dependencies between payment strategies or how to handle exceptions in a way that maintains clarity and avoids overly complex error handling.
Why does comment sound like AI to me? 🤔
Thanks for your suggestion 🙂
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 :)
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
@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
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.
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!
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 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.
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 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. Clearly explained how we can make use of these concepts. Appreciate it.
Thanks 🙂
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.btw, you are still using
if
in the PaymentService, also strategy.get probably uses 'if'Great article!
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.
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.
Based on your example, I'll go with if-else. Simpler and cleaner. You can refactor it once it becomes bigger.
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...
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?
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.
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?
I wrote almost this code a few years ago.