+3
На рассмотрении
Interface vs Factory method
Hello, going through factory method I still dont understand why we have to go through all the hustle of implementing it when we can just use interface alone and make a direct construction from the class that implement it. For example:
interface User {
getName: string;
getToken: string;
}
class Vendor implements User {
getName(){
return 'some name';
}
getToken() {
return 'some token';
}
}
class Buyer implements User {
getName(){
return 'some name';
}
getToken() {
return 'some token';
}
}
const vendor = new Vendor();
const buyer = new Buyer();
Now if there are more type of user, we can simply just use interface and make a direct construction from its class. Why is a factory method a better choice in this case ? Sorry I might have not understood it clear.
interface User {
getName: string;
getToken: string;
}
class Vendor implements User {
getName(){
return 'some name';
}
getToken() {
return 'some token';
}
}
class Buyer implements User {
getName(){
return 'some name';
}
getToken() {
return 'some token';
}
}
const vendor = new Vendor();
const buyer = new Buyer();
Now if there are more type of user, we can simply just use interface and make a direct construction from its class. Why is a factory method a better choice in this case ? Sorry I might have not understood it clear.
Сервис поддержки клиентов работает на платформе UserEcho
Avoiding the direct construction of products on the client code is a whole point of the pattern. If you don't have this problem, you don't need to apply the pattern. If you can get away with a simple interface, then do it—the simpler the code, the better.
thank you for your answer :)
Thanks for your response. One more question about your answer: As you explained, the factory method avoids the direct construction of the products on the client side, but the client still have the responsibility to decide/construct the correct factory. Why is this a good solution for the client? I mean, from the point of view of the client, isn't the same problem (but now with more code to understand)? On the other hand, I understand that the code in charge of calling the "new" operator is cleaner, can be split apart so it's more independent and maintainable and at the same time is open-closed. Thanks you very much for your hard-work!
In my experience, the "modern OOP" is all about pushing the ugly stuff under the rug (to the client code). For example, a framework or a library that you're using might be a pinnacle of design, but it requires you to write a ton of ugly configurations to start the thing. It's generally unavoidable to have this sort of code somewhere, and the most that you can do is to move it to a single place and make it as small as possible.
I understand your point, I've worked with a production 20 year old legacy code of 2 or 3 million LOC, and I feel two-sided about it: on one hand is amazing how this code works and collaborate each class with each other, and on the other hand, I feel really bad for the implicit complexity it have (the churn rate was really high), in my POV this complexity was exacerbated by our ignorance of good patterns, dead-lines with clients, and somewhat a kind of fear to ask "what should be a good and clean way to implement this feature, or correct this bug?". In any case, and as more as I learn, the "ugly code" seems unavoidable, which talks really bad about our capacity as humans beings to control our creations (in this case, coding).
I do feel very appreciate for your work, I think that the project factoring.guru talks directly to the problem I've commented, and I'm sure it make the life of other programmers much easier.
Yeah, I think a lot about it as well. All the refactoring is only needed for us, humans. If AI will ever learn to code, I doubt it ever needs to refactor anything at all, it will comprehend the ugly code just fine: "it's good as long as it works".
This summaries the issue I had when using the abstract factory pattern and possibly similar to your issue in your other forum post, my client code needed to create similarly structured products from every file within a directory based on their name.
The files had standardised names and standardised file suffixes, e.g. fileA.txt, fileB.txt, fileA.pdf, fileB.pdf... so on. in any order and any number.
Instead of using the client to implement a for loop which directly created instances of the exact product associated with the exact file... you can create a factory for the each of the variables with the least variation (in my case the file suffixes). These factories themselves are an instance of an Abstract Factory Class, and they all implement methods which create products based on the file name.
This way the client code does have a decision to make, but its quite a simple for loop. Now, only one variable is filtered by the client to the correct factory. The correct factory uses the remaining variable (in this case, file name) to decide which product creation method to use. Product creation incidentally needed some extra logic related to the contents of the file, and this could also be handled by the factory pre or post product creation, but before handing the product back to the client.
pseudo_code something like:
folder = [file1.txt, file2.txt, file3.txt, file1.pdf, file2.pdf, file3.pdf]
client_create_products(folder):
for i in folder:
if i.suffix == txt
txt_factory.filter_name(file.stem)
# The filter_name method internally calls a create_product() only after it decides which one to use
elif i.suffix == pdf
pdf_factory.filter_name(file.stem)
If there are many variables that decide which factory and product to create, you could always create a factory factory and sequentially pass variables down the line... but I'm not sure how many levels of recursion would be acceptable lol. Although with this method you can handle exceptions before or after product creation and at the appropriate level without breaking the initial loop!