I don't know if I got ur point but I'll try to explain further:
This code:
classPhotoViewer{voidopenPhoto(Stringtype){if(type=="JPEG"){System.out.println("Open JPEG photo!");}elseif(type=="PNG"){System.out.println("Open PNG photo!");}else{System.out.println("Photo type is not supported!");}}}
You don't have to check anything in the latter code. PhotoViewer only cares about dealing with any instance of a Photo class to open it. So, you can have an array of different photos and open any one of them using PhotoViewer. If you try to add a new Photo type you don't have to check anything or change the behavior of the PhotoViewer, just add a new photo. Also, you've to know that if you decided to use the simple Factory pattern to create your photo objects it will obviously violate the Open-Closed principle as you said. Check this link for more details: softwareengineering.stackexchange....
Violating the Open-Closed principle to create objects using Factory doesn't mean you've to make other parts violate it. This part of the example only explains what the Open-Closed principle says.
in the first code, you open the photo simply like this
photoViewer.openPhoto(photoType);
but you had "ugly" if inside openPhoto method that you didn't like.
So you refactored it to get rid of it. You created a bunch of classes, an interface. But now you have a problem because you still only have the string representing the photo. How can you change string photoType to correct class implementing Photo interface?
varphotoType="jpg";varphotoViewer=newPhotoViewer();varphoto=???// how to solve this?photoViewer.openPhoto(photo);
so you have the same "if" as before. But now you have a bunch of classes and an interface on top of that. So your code still breaks the principle the same way. There are just more classes + higher abstraction = complex code, but you still haven't solved the core issue why you even started refactoring in the first place and that is that it breaks open-closed principle.
You can also add even more abstraction and make the code even more complex using factory pattern. But again, yes, now the previous code doesn't break the principle:
So once again, your code still breaks the principle.
So you had a code that was breaking the principle. You made some changes, added a lot of abstraction and the core problem that your code is breaking the principle is still there.
I just don't understand why shifting and hiding the problem under layers of abstraction is called better code.
Now I got your point. Actually, you're right about that. The factory pattern somehow violates the open-closed principle, but its violation is not the worst and you can deal with it if you apply the pattern correctly. You can't always apply the principle as the book says. But you can always try to reduce and control the violation.
Imagine if the photo has open, close, and share functions.
classPhotoViewer{voiddoSomethingToPhoto(Stringtype,Stringaction){if(type=="JPEG"){if(action=="open"){// do something}elseif(action=="close"){// do something}elseif(action=="share"){// doe something}}elseif(type=="PNG"){if(action=="open"){// do something}elseif(action=="close"){// do something}elseif(action=="share"){// doe something}}else{if(action=="open"){// do something}elseif(action=="close"){// do something}elseif(action=="share"){// doe something}}}}
You can see that this is one of the worst things you can do to add those functionalities. So, the correct way is to create a Photo interface and force every new photo type to implement. Even if that shifted the violation to use the Factory pattern. You can control its behavior and limit the problems to the creation only. Because it's a well-known design pattern.
I hope I answered your question clearly and I will try to edit the example to become clearer. Also, try to read this article it's useful and talks about that:
I don't know if I got ur point but I'll try to explain further:
This code:
is replaced with this one:
You don't have to check anything in the latter code. PhotoViewer only cares about dealing with any instance of a Photo class to open it. So, you can have an array of different photos and open any one of them using PhotoViewer. If you try to add a new Photo type you don't have to check anything or change the behavior of the PhotoViewer, just add a new photo. Also, you've to know that if you decided to use the simple Factory pattern to create your photo objects it will obviously violate the Open-Closed principle as you said. Check this link for more details:
softwareengineering.stackexchange....
Violating the Open-Closed principle to create objects using Factory doesn't mean you've to make other parts violate it. This part of the example only explains what the Open-Closed principle says.
I can see that I wasn't clear enough so I will try to explain better.
You have a string representing a photo and PhotoViewer class just as you had before.
in the first code, you open the photo simply like this
but you had "ugly" if inside openPhoto method that you didn't like.
So you refactored it to get rid of it. You created a bunch of classes, an interface. But now you have a problem because you still only have the string representing the photo. How can you change string photoType to correct class implementing Photo interface?
you can either create if statement
so you have the same "if" as before. But now you have a bunch of classes and an interface on top of that. So your code still breaks the principle the same way. There are just more classes + higher abstraction = complex code, but you still haven't solved the core issue why you even started refactoring in the first place and that is that it breaks open-closed principle.
You can also add even more abstraction and make the code even more complex using factory pattern. But again, yes, now the previous code doesn't break the principle:
But once again, it is just shifting the if somewhere else (this time to the factory).
So once again, your code still breaks the principle.
So you had a code that was breaking the principle. You made some changes, added a lot of abstraction and the core problem that your code is breaking the principle is still there.
I just don't understand why shifting and hiding the problem under layers of abstraction is called better code.
Now I got your point. Actually, you're right about that. The factory pattern somehow violates the open-closed principle, but its violation is not the worst and you can deal with it if you apply the pattern correctly. You can't always apply the principle as the book says. But you can always try to reduce and control the violation.
Imagine if the photo has open, close, and share functions.
You can see that this is one of the worst things you can do to add those functionalities. So, the correct way is to create a Photo interface and force every new photo type to implement. Even if that shifted the violation to use the Factory pattern. You can control its behavior and limit the problems to the creation only. Because it's a well-known design pattern.
I hope I answered your question clearly and I will try to edit the example to become clearer. Also, try to read this article it's useful and talks about that:
sergeyzhuk.me/2018/01/25/factory-m...
Drop the if and generate the class name, quick cut:
(Untested PHP, but I’m mobile right now)