tospo has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,
I'm designing a system that should use the builder pattern (I think...) to build a complex product, all orchestrated by one Director class. The real problem is a bioinformatics one and difficult to explain to non-biologists, but this here is essentially the same in a more "real-world" example.
Let's say we have a class representing a buyer. A buyer requests a new vehicle and the VehicleDealer then gets a VehicleBuilder to build the vehicle, which could be a Car or a Motorbike, so the concrete builder class will be a CarBuilder or a MotorbikeBuilder:

################ ################# # VehicleBuyer # --> # VehicleDealer # ################ ################# | V ################## # VehicleBuilder # ################## | ---------------+----------- V V ############### #################### # CarBuilder # # MotorbikeBuilder # ############### #################### | | V V ######## ############# # Car # # Motorbike # ######## #############
So far so good but my problem now is that a vehicle has lots of parameters, let's say in this case all the customizable details like outside/inside colours and materials etc.

My problem now is that the VehicleDealer and the VehicleBuilder and of course the concrete Product classes (Car and Motorbike) all need to have attributes for all of the parameters I can pass around.
At first I implemented these attributes (I'm using Moose by the way) in each of those classes but that was a lot of duplication, so now I moved them all into Moose roles and consume the roles.
Now I have much shorter code for those classes but I can see problems maintaining this because the attributes that any one of those objects has are spread across several roles and in the end I still have to document each class, so basically I'll end up duplicating, if not the code, then at least the documentation for all those parameters.
My question: how do others deal with a problem like this? Maybe I'm missing a design pattern that would help me out here? Maybe ther just isn't a better way of doing this - just thought I'd ask...
Thanks for your help!!

  • Comment on Builder design pattern with lots of parameters - trying to declutter design
  • Download Code

Replies are listed 'Best First'.
Re: Builder design pattern with lots of parameters - trying to declutter design
by BrowserUk (Patriarch) on Mar 28, 2011 at 18:38 UTC

    My take on this is that you are making the mistake of trying to encapsulate program logic into your class hierarchy.

    That is, you are trying to avoid

    my $dealer; if( $vehicleType eq 'car' ) { $dealer = CarDealer->new(); { elsif( $vehicleType eq 'bike' ) { $dealer - BikeDealer->new(); } else { die "Unknown Vehicle type: $vehicleType"; }

    And by doing so, you are pushing the decision into the class hierarchy and compounding its complexity in the process.

    There simply isn't enough commonality between the two to root them in a common ancestry.

    For (say) a supermarket where the only variables in a purchase might be pack size and quantity, it might make some sense; but for something with as many configurable options as cars and bikes, using inheritance to avoid an early boolean decision seems like a Code Smell of the contrived complexity variety.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Thanks for your reply!
      In my real application there is maybe a bit more communality but I'd say even in this example there probably is. Even in the real world you may find VehicleDealers who do cars and bikes because all they need to do is call up the builder/factory to make a vehicle and maybe give them some of the details such as colour, and these are mostly the same options for both types of vehicles. As far as I can see, if I used your example, I would still end up dealing with pretty much the same parameters/attributes in the concrete builders and product classes, which was my original problem. However, I think that the mistake was to try and make the builders check those attributes instead of letting the product classes deal with it.
Re: Builder design pattern with lots of parameters - trying to declutter design
by jethro (Monsignor) on Mar 28, 2011 at 16:53 UTC

    I'm no expert in object oriented programming, but I would think that for example the VehicleDealer class doesn't need any attributes belonging to a car or Motorbike. Instead it will delegate those details it gets as a parameter to the VehicleBuilder which in turn delegates to the CarBuilder. And the CarBuilder will at last call new with those parameters so that the attributes are set. Only the car class should have an attribute like outside color or inside color, while the Builders might have methods like paint or configure.

    Check out the wikipedia example Builder_pattern. Note that only the actual pizza has an attribute dough. Ok, the builders have a method for every attribute. if you want to avoid this, one method would handle a group of connected attributes (i.e. if you specify outside color green, the method knows a default matching color for the inside).

      OK, yes, I'm afraid in this respect this example may not accurately reflect my real problem. One of the reasons I wanted the class "VehicleDealer" to have those attributes is that it should be able to verify that it has all the information it needs to forward the real work to the Builder. This is because the actual job may be time consuming and I want to be able to throw errors immediately if the parameter set is incomplete or inconsistent, but maybe that's not such a good idea after all...
      I guess I could easily separate instantiating and running the builders so that I can have them check their parameters before running the job. Thanks for your help!
Re: Builder design pattern with lots of parameters - trying to declutter design
by locked_user sundialsvc4 (Abbot) on Mar 28, 2011 at 16:08 UTC

    Here are some “thoughts purely of my own” which come to my mind immediately when I read this ... and, mind you, I’m using my own made-up (I hope, common-sense) terminology.   Please don’t flip through design-pattern textbooks trying to figure out which one of those I am referring to.   This is coming from my own cranium.

    It may be that you are exposing all of those attributes so that different other actors can make appropriate decisions using them.   The problem here is that every actor you meet has to be familiar with every product it may meet, either now or in the future.   Likewise, when new actors are invented, the logic which deals with “all those attributes” must be duplicated into them.   Pretty soon you have exactly the web of interdependency that you would like to avoid, even though it has been couched in the latest trendy metaphors.

    Having spent a few seconds now groping for an analogy ...   For that purpose, I like to coin the notion of what I shall call an “apprentice.”   An apprentice is the fellow who tags along beside the master in the shop, helping the master out and in the process learning his trade.   The apprentice is also, quite admittedly, the “grunt.”   Well, in this case, apprentices are the folks who can answer a product’s specific questions about a builder, and a builder’s specific questions about a product, and who are able to determine whether they actually possess the knowledge necessary to speak-up in the first place.   There might be any number of these, and when there is a need to get an actor and a product together, we have to find the apprentice that is most knowledgeable – who is the “best fit.”

    An apprentice, interviewing for the job as it were, might ask of the product, “do you have parameters X, Y, Z?”   And of the actor, “do you need to know A, B, C?”   Pause.   “Then I can help you, and my fitness score is 21.”

    The purpose of the apprentice is to answer questions, and to do grunt work.   An arbitrary number of them can exist and perhaps more than one of them are participating at any time.   The complexity of this so-to-speak “cartesian join” is now wrapped-up in the implementation of the apprentice, and of the apprentice-selection heuristic.

    I do not intend to suggest that “apprentice” is the best word to use here.   I didn’t read it in a book; I just now made it up.   In fact it really isn’t the best word or the best analogy.   The notion is basically that of a “plug-in, hot-swappable software subject-matter expert,” who enables the system to be flexible more-or-less “by committee.”   If a VehicleBuilder or even a VehicleBuyer needs to know the answer, they don’t have to have the logic to determine the answer themselves ... they just have to find someone who knows is the most confident that he has the answer, and then ask him to produce it.   I think that the germ of the idea is a sound one, and I do not proclaim it to be original.   (And if it does happen to be original, you will not be asked to buy my book nor to attend my seminar anytime soon.)

      So in essence you would create additional classes that are basically ParameterHandlers (maybe "Catalogs" would be an analogy that would fit here?), is that correct? Directors and Builders would then only need to use the same Catalog to determine what they can and should know about the object to be created.

      If I understand you correctly then this is something I also thought about. The advantage would be that it would be clearer where to find these parameters and not be surprised if an object of a class has lots of attributes that come from its various mixed-in roles.
      Maybe this isn't at all what you meant but I think I'm warming up to the idea anyway.... :-)

        This idea is “not even half-baked ... it’s raw dough.”

        I don’t think that “Catalog” is a good metaphor, because, in the real world, “a catalog” is a thing that you use, while it just sits there.   What I am describing here is an active thing:   an intermediary, a concierge, a lackey, a grunt, an engineer on the butt end of the org chart.

        Essentially, you have a bunch of “players” here ... cars, dealers, factories and so-on ... “that have to be able to get their questions answered and to do things.”   Furthermore, all of these various groups of players are constantly changing as the application evolves.   So you create a concept of specific intermediaries ... a “secretarial pool” of experts who can be called-upon, first to decide if they can help you, then to help you if they can.   You can engage as many of them as you need.

        These so-called “lackeys” are, of course, as mission-critical as they are unsung.   (’Twas ever thus...)   They bear the triple responsibility of:

        1. Deciding, and grading, their own fitness to a particular purpose.
        2. Understanding what all the relevant knobs, switches and flashing-lights are, for anyone whom they must deal with (both “the requestor” and “the device”).
        3. Concealing all of that irrelevant detail from all parties concerned, so that they can accomplish their purpose without raising their scalp above the top-edge of the trenches.

        I am attracted to the idea because that more-or-less is how things work in the real world (of engineering).   No matter who you are, you cannot know everything and you cannot afford to learn it.   So, the task quickly becomes, “find someone who knows.”   Since you, of course, do not know how to judge who is qualified and who is not (and since that can change at any time without your ability to know), you put forth a cattle-call and ask for volunteers to step forward.

        We can always put forth a more-conventional design that exploits what we today know to be similarities and differences between “cars” and “motorbikes,” but over (a sometimes short period of time) those assumptions become strained.   An executive suddenly decides that it’s a great idea for the company to start producing microwave ovens, or yogurt, and presto, it is done.   In a real-world situation (after burying the aforesaid executive under a great mound of cheese), the company would be amassing a multi-disciplinary group of people who do know how to fill the gaps of knowledge and expertise.   We have not taught the old dogs new tricks.   Instead, we have enabled everyone to adapt themselves to this discipline, which can accommodate yogurt-making and car-making under the same roof.

Re: Builder design pattern with lots of parameters - trying to declutter design
by repellent (Priest) on Mar 29, 2011 at 05:43 UTC
      My problem now is that the VehicleDealer and the VehicleBuilder and of course the concrete Product classes (Car and Motorbike) all need to have attributes for all of the parameters I can pass around.

    What if you had the notion of a VehicleSpec object that can respond differently to each product class? It will also only allow setting attributes depending on who the caller is (e.g. a Car-type class has no place dictating how long the hand clutch would be). Then each product class will only need a single attribute for the specification it needs.

    Just my 2cents. Not sure which direction this will push your code in.
      That would be sort of simliar to the "Catalog" class I mentioned above in that the parameters taht go into a Vehicle are combined into their own class and can tehn be passed around as instances of it, right?

        Moose has introspection capabilities. Your VehicleDealer can find out what attributes a class has (even before that class is instantiated). If you name your attributes so that they can be identified (i.e. all configuration attributes of class car have a prefix of 'config_') or if simply all attributes of class car are to be configured by VehicleDealer, you don't need any of the attributes in VehicleDealer nor any intermediate classes with attribute lists.

        Even without introspection I would just have a class method in car and motorbike that just returns all the attributes it possesses. So that the information is kept in one place only.

Re: Builder design pattern with lots of parameters - trying to declutter design
by wfsp (Abbot) on Mar 30, 2011 at 11:45 UTC
    I think the idea of a catalog/spec object (Vehicle) could be the way to go. The only mandatory parameter for the customer would be Type everything else could by optional i.e. defaults. The default colour could be, say, black. :-) Validate, give it an id, a date and add to a Vehicles object (front end to a db).

    Pass the Vehicle->id to whoever needs it. Extra parameters could be added and validated at each stage of the chain and passed on along.

    The Vehicles object would allow querying of the db by each part of the chain to establish, say, how many cars, how many bikes. Pass Vehicles an id and get a Vehicle back, perhaps to check the status, e.g. not started, started, completed. The Vehicle_Builder might want to know what new orders have come in today (Vehicles->today). The Car_Builder would want to know if the paint shop has to get a different pot of paint from the store (grrr! customers!!).

    Adding a layer of abstraction has reduced all the parmaters to one, the id. It's all been encapsulated in black boxes. Neither Vehicle nor Vehicles know or care about customers, dealers, builders (boo introspection! :-). They know about colours and dates but little else.

    While you're at the paper and pencil stage is a good time to nail down the APIs. Hard. I believe the API is key, get it right and the code writes it self. Well chosen object names and methods and the code will "read" well too. And it will be short, a good thing, but be careful not to put the business model (logic) in the objects or you could find yourself in a straight jacket. Get those flow charts right first!

    The above is the extent of my experience with OO, so, while no expert I have found this much very helpful. The discussion in that thread is also very useful as it takes up the question of how much you put in an object.

    And, of course, there are many other ways to do it :-)

    Good luck!