Is using the Factory or Builder pattern nessesary?

Started by
21 comments, last by LorenzoGatti 7 years, 11 months ago

Let's assume I have the following class:


public abstract class Client {
    
    private String clientID;
    private String clientFirstName;
    private String clientLastName;
    
    public Client(String ID, String firstname, String lastname)
    {
        this.clientID = ID;
        this.clientFirstName = firstname;
        this.clientLastName  = lastname;
        
    }
}

and the following Subclasses:



public class Domestic extends Client {
    public Domestic(String ID, String firstname, String lastname) {
        super(ID, firstname, lastname);
        
    }
}

public class International extends Client {

    private List<String> documents;
    
    public International(String ID, String firstname, String lastname, List<String> documents) {
        super(ID, firstname, lastname);
        
        this.documents = documents;
        
    }
}

Given that both subclasses have a different set of parameters, the International subclass requires a List of documents(passport, drivers license), while domestic doesn't. To me anyway, I don't believe the factory pattern is adequate because of the different constructor parameters, and the builder patter isn't necessary as all arguments are necessary, an there isn't that many of them. So is doing this okay?


Client international = new International(id, firstname, lastname, documents); 

or if there is a specific method that I need to access in the International class:


International internationalObj = new International(id, firstname, lastname, documents);

Questions:

1. Is it mandatory to use the factory or builder pattern given this situation?

2. Is there a downside to doing to doing it without the factory or builder?

Advertisement
There are no mandates in programming. Do whatever will make the code more clear. Using a factory or builder is an attempt at restricting what parts of the code need to know about the difference between Domestic and International.

But it looks like your design is doomed to begin with. How are the documents going to be used? Since the base class doesn't expose any virtual functions that may make use of them, you are probably going to be needing to know the type of client in some other part of the code.

I would personally add a variable to Client indicating whether it's international or domestic, and leave the list of documents empty for domestic clients.

There are no mandates in programming. Do whatever will make the code more clear. Using a factory or builder is an attempt at restricting what parts of the code need to know about the difference between Domestic and International.

But it looks like your design is doomed to begin with. How are the documents going to be used? Since the base class doesn't expose any virtual functions that may make use of them, you are probably going to be needing to know the type of client in some other part of the code.

I would personally add a variable to Client indicating whether it's international or domestic, and leave the list of documents empty for domestic clients.

Thanks for the reply

I left out the rest of the implementation for simplicity. There is a method that will use the documents List that I've declared.

Why do you want to do this?


Client international = new International(id, firstname, lastname, documents);

And not this?


International international = new International(id, firstname, lastname, documents); 

Yes, there are valid reasons for the first, but what is your reason? You clearly know, in-scope, that you want an International. If you plan to return that out-of-scope, then it looks to me very much like you're already using something like a factory. If you're only using it in the current (and underlying) scope, then polymorphically making it a Client is redundant.

Why do you want to do this?


Client international = new International(id, firstname, lastname, documents);

And not this?


International international = new International(id, firstname, lastname, documents); 

Yes, there are valid reasons for the first, but what is your reason? You clearly know, in-scope, that you want an International. If you plan to return that out-of-scope, then it looks to me very much like you're already using something like a factory. If you're only using it in the current (and underlying) scope, then polymorphically making it a Client is redundant.

No particular reason. I was just showing the ways I could create the International subclass. Ideally I would use the second approach, however, I was reading about the factory pattern and became confused as to when to apply them.

The only thing you're required to have in programming is the main function. Otherwise it's free game.

Domestic shouldn't be there and Client shouldn't be abstract. Literally no difference between the classes in your example. Either you got a client with just an id, or an international client with a list of ids.

Dont make classes just because. For a subclass to exist it has to either have different behavior (methods) or different state (fields) than the superclass. Otherwise it has no purpose.

Hell you could remove International/Domestic altogether, remove the ID field from Client, and just let Client have a documents list, some will only have an Id, some will have passports/driver licences.

Also you should respect standard naming schemes: ID == bad, id == good. clientID == bad, clientId == good.

Have the constructor enforce invariants, can an id be null? Can a last name be null? Can a first name be null? Strict API leads to less bugs.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

Domestic shouldn't be there and Client shouldn't be abstract. Literally no difference between the classes in your example. Either you got a client with just an id, or an international client with a list of ids.

Dont make classes just because. For a subclass to exist it has to either have different behavior (methods) or different state (fields) than the superclass. Otherwise it has no purpose.

Hell you could remove International/Domestic altogether, remove the ID field from Client, and just let Client have a documents list, some will only have an Id, some will have passports/driver licences.

Also you should respect standard naming schemes: ID == bad, id == good. clientID == bad, clientId == good.

Have the constructor enforce invariants, can an id be null? Can a last name be null? Can a first name be null? Strict API leads to less bugs.

Thanks for your reply.

The example I posted is a stripped down version of 2 subclasses that actually have a lot more that was is shown here. My real question, and I guess I should have been more clear about it, is it mandatory that I use the builder/factory pattern? The reason why I ask is, the examples I've seen of the factory pattern use no argument constructor to build the objects. However, what if you have subclasses that have slightly different parameters specific to the subclass, what do you do in that case? What happens if you don't have a no argument constructor?

My real problem is that I find the factory pattern confusing and hard to understand despite several attempts at trying. To me, I understand the code shown below a lot better than calling/using a factory to do it. So, my second question is, is it okay just to leave it like this (code below)?


Client international = new International(id, firstname, lastname, documents);
International international = new International(id, firstname, lastname, documents);

The example I posted is a stripped down version of 2 subclasses that actually have a lot more that was is shown here. My real question, and I guess I should have been more clear about it, is it mandatory that I use the builder/factory pattern?

Unless you have strict rules in place (e.g. homework or coding guidelines stating rules explicitly), no specific pattern should ever be considered mandatory.

Don't introduce patterns if you don't feel they belong.

Don't try to make your problems fit patterns you know, just to have a reason to use those patterns.

Hello to all my stalkers.

>> I was reading about the factory pattern and became confused as to when to apply them.

you do that with algos, not patterns.

folks seem to miss that bit. algos are implementation methods that often have best use cases associated with them (IE its generally known when and where they perform well and poorly). algos are what you consider and choose from for code implementation. technically speaking, patterns are a generic way to describe the solution post mortem, nothing more. due to the fact that a pattern can be similar to an algo, folks sometimes treat patterns as algos. and worse yet, they think they are the only algos, or somehow superior. when in actuality they are recurring patterns of code organization commonly found in non-realtime business apps. which is probably one strike against them right out of the gate when considering them for realtime game use. non-realtime business apps have little in common with realtime modeling and simulation software (IE games). take a look at the projects the "new gang of four" looked at when writing their design patterns book. any of them games? No? didn't think so.

so the question should be "is this algo (not pattern) required?"

given that main() is the only thing required, the obvious answer is no.

so the question really should be "whats the best algo to do this?"

figure that out, implement it, then see what pattern it looks like. that's how you determine "what pattern to use". odds are a proper implementation will be a "game pattern" not a business app pattern, or it will be a design principle that already existed that they have renamed for their book (such as flyweight, SRP, etc. all very standard design stuff that's been around a lot longer than c++).

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

This topic is closed to new replies.

Advertisement