I have seen it written in multiple threads/comments on stackoverflow that using switch
is just bad OOP style. Personally I disagree with this.
There will be many cases where you cannot add code (i.e. methods) to enum
classes you want to switch on because you don't control them, perhaps they are in a 3rd-party jar file. There will be other cases where putting the functionality on the enum itself is a bad idea because it violates some separation-of-concerns considerations, or it is actually a function of something else as well as the enumeration.
Last of all, switches are concise and clear:
boolean investable;
switch (customer.getCategory()) {
case SUB_PRIME:
case MID_PRIME:
investible = customer.getSavingsAccount().getBalance() > 1e6; break;
case PRIME:
investible = customer.isCeo(); break;
}
I'm not defending every use of switch
and I'm not saying it's always the way to go. But statements like "Switch is a code smell" are just wrong, in my opinion. Does anyone else agree?
Sure switches are poor OO, you shouldn't put a return in the middle of a function, magic values are bad, references should never be null, conditional statements must go in {braces}, but these are guidelines. They shouldn't be followed religiously. Maintainability, refactorability, and understandability are all very important, but all second to actually getting the job done. Sometimes we don't have time to be a programming idealist.
If any programmer is to be deemed competent, it should be assumed he can follow guidelines and use the tools available with discretion and it should be accepted that he will not always make the best decision. He may choose a less-than-optimal route or make a mistake and run into a hard-to-debug problem because he chose a switch when maybe he shouldn't have or passed around too many null pointers. That's life, and he learns from the mistake, because he is competent.
I don't religiously follow programming dogma. I consider guidelines in the context of myself as a programmer and apply them as seems reasonable. We shouldn't harp on these sorts of programming practices unless they are fundamental to the problem at hand. If you want to assert your opinion on good programming practices, it's best to do so in a blog or an appropriate forum (such as right here).
I find nothing wrong with using the switch statement in OO code. My only criticism is that I would have made a new method on Customer called IsInvestible which hid this logic. There is 0 wrong with using an switch statement as the internal implementation of this method. As you've said you can't add methods to enum's but you can add more methods to Customer.
In the case you don't have access to the source, I'd say a non-instnance method is fine. An OOP purest would require a brand new object but that seems like it may be overkill in this case.
I think statements like
and
are oversimplifying. The truth is that case statements that are switching on type are bad OOP style. These are the ones you want to replace with polymorphism. Switching on a value is fine.
My issue with switch statements is that in real world application there are rarely switch statements that exist in isolation.
A lot of the code that required refactoring in my company's codebase would have entire classes riddled with multiple switch statements throughout such that you had to know of the existence of every single switch statement.
Ultimately, the cleanest refactoring the entire system into a Strategy pattern with a Factory controlling the creation of the strategies based on the single remaining copy of the switch statement.
Due to time constraints we didn't take it any farther because this served our needs. There was still a big giant switch statement, but there was only one, so adding additional strategies only required ipmlementing the interface and adding the creation step to the master switch statement.
I do believe switching on type is a code smell. However I share your concerns about separation-of-concerns in code. But those can be solved in many ways that allow you to still use polymorphism, e.g. the visitor pattern or something similar. Read up on "Design Patterns" by the Gang of Four.
If your core objects like Customer stays fixed most of the time but operations change often, then you can define operations as objects.
This looks like overkill, but it can easily save you a lot of coding when you need to handle operations as collections. E.g. display all of them in a list and let user select one. If operations are defined as functions you easily end up with a lot of hard coded switch-case logic, multiple places which needs to be update each time you add another operation, or product as I see it referred to here.
I view switch statements as a more readable alternative to if/else blocks.
I find that if you can boil down your logic to a structure that can be evaluated integrally, the code is likely to be providing a level of encapsulation that is required in OOP.
At some point real (messy) logic has to be written for a practical program to ship. Java and C# are not strictly OOP languages, given that they inherit from C. If you want to enforce strictly OOP code, then you'll need to use a language that does not provide idioms which violate that mindset. My view is that both Java and C# are intended to be flexible.
One of the things that made VB6 so successful, oddly enough, is that it was Object-based, not Object-oriented. So, I would say that pragmattic programmers will invariably combine concepts. Switch can also lead to more manageable code, as long as there is decent encapsulation already programmed in.