tag:blogger.com,1999:blog-6243670623010502252.post6052303990542178509..comments2022-04-01T22:16:03.957+01:00Comments on Remove duplications and fix bad names: Step Builder patternUnknownnoreply@blogger.comBlogger19125tag:blogger.com,1999:blog-6243670623010502252.post-79383707521704118162012-09-23T13:18:11.517+01:002012-09-23T13:18:11.517+01:00I really thanks for your sharing about this. I do ...I really thanks for your sharing about this. I do not mean to criticize by any means. I just want to point out some "weakness" of this approach (from my point of view only) and I hope that we can discus to improve the solution as whole.<br />You are right, maybe in your use cases, this approach is suitable.Trương Xuân Tínhhttps://www.blogger.com/profile/06494927095356964880noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-62118687645620814472012-09-23T13:13:21.341+01:002012-09-23T13:13:21.341+01:00"And what happens when your client wants to s..."And what happens when your client wants to set this to a non-default value, they have to add a new withBlahBlah() call"<br />As you can see, a client code change was originated from the client need :). <br /><br />"I can just as easily make the change in the domain model from the step builder and set new properties to default values in the intialization of this object from the step builder without changing the client code."<br />In that case, does your new required property need a "required step" in the call chain? If the answer is yes, you are in a serious problem. You have to change the client code for all the use cases (even the client code does not want to set a non-default value). If the answer is no, then is it a real "required" property? Why do I have to set a default property for a non-required property?Trương Xuân Tínhhttps://www.blogger.com/profile/06494927095356964880noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-42549911707764532512012-09-21T12:19:19.558+01:002012-09-21T12:19:19.558+01:00You add a required field and the client will not k...You add a required field and the client will not know what is required. <br />For example, when I came up with this pattern, I was writing an API that involved the creation of an Object in charge of connecting to a file. This file can be local or remote. In case it's remote the step builder is forcing the client to add "user" and "password" as a required step, in case of local the client does not have the possibility to add "user" and "password".<br />Also, you can add default values in the step builder like you do in the normal builder.<br />To add a new MANDATORY step you need to release a new version of your API. If the client switch to this version he will need to add the MANDATORY field, simple!<br />Anyway, normally you find out all the mandatory fields during design process, but, yes it can happen that you need to add something mandatory at some point(it's very rare) and in this case, if the client wants to upgrade the API, he needs to adapt his code to the new version.<br />To finish, with step builder pattern I do not want to complete replace the normal builder, but just offering a different approach to the same problem. If you recon that in your code the normal builder fit better, just use the normal builder.marcocasthttps://www.blogger.com/profile/09589835245958019484noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-90573922051605576632012-09-21T12:12:09.152+01:002012-09-21T12:12:09.152+01:00"With this approach, when I add another requi..."With this approach, when I add another required field, I just modify the BuilderFactory to include the new property through the new constructor of the builder. No need to change the client code for that."<br /><br />And what happens when your client wants to set this to a non-default value, they have to add a new withBlahBlah() call<br /><br />A client code change. And you have just introduced another layer of obscurity.<br /><br />I can just as easily make the change in the domain model from the step builder and set new properties to default values in the intialization of this object from the step builder without changing the client code.<br /><br />Simple fact is the client code will have to change to support a non default value.Anonymoushttps://www.blogger.com/profile/06617380794127685471noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-76006760934320174552012-09-21T11:11:24.543+01:002012-09-21T11:11:24.543+01:00Break client code is not fun :).
The traditional b...Break client code is not fun :).<br />The traditional builder pattern does not have this problem (actually it does have problem, but with Factory Method pattern in place, everything is fine)<br />About your arguments:<br />>It does not really guide the user through the creation.<br />As the client code developer, I really don't care about how to create my object. That purpose of the builder pattern! Abstract the way to construct a "valid" object.<br />>A user can always call the build method in any moment, even without the needed information. <br />Then you use the builder pattern wrong! Your builder must always create a valid object whenever the "build" method is called.<br />> There is no way to guide the user from a creation path instead of another based on conditions. <br />You are right at this point.<br />>There is always the risk to leave your object in an inconsistent state.<br />If you implement the builder pattern correctly, this will never happen.<br />>All methods are always available, leaving the responsibility of which to use and when to use to the user who did not write the api.<br />Then the user of the api can override any "default" value of all the required properties.<br /><br />The "correct" way (from my opinion): for all the required properties, the builder should provide a constructor to take all the values for those properties, but when you add another required property, this will break all the client code. There is one way to fix this. Just make builder constructors inaccessible from client code and wrap around that with a Factory method pattern, something like:<br />public class BuilderFactory {<br /> public DomainObjectBuilder aDomainObject() {<br /> return new DomainObjectBuilder(defaultRequiredProp1, defaultRequiredProp2)<br /> }<br />}<br /><br />So your client code will look like this:<br />DomainObject object = BuilderFactory.aDomainObject().withBlah(value1).withBlahblah(value2).build();<br />With the help of static import, it will look like this:<br />DomainObject object = aDomainObject().withBlah(value1).withBlahblah(value2).build();<br />With this approach, when I add another required field, I just modify the BuilderFactory to include the new property through the new constructor of the builder. No need to change the client code for that.<br />With your "step" approach, it's not that easy to do an ad-hoc customization for one of required properties. You force the client to call the method that they may not want to.<br />It's just my 2 cents though.<br />Feedback is welcomed.Trương Xuân Tínhhttps://www.blogger.com/profile/06494927095356964880noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-17725281186456971782012-09-17T23:30:26.398+01:002012-09-17T23:30:26.398+01:00Hey Trương, not sure I understood exactly what you...Hey Trương, not sure I understood exactly what you meant, but If you need to add a required property, you should break the client code! This is all the purpose of this pattern. If the property is optional, you just add a method in the step interface and you will not break the client code.<br />marcocasthttps://www.blogger.com/profile/09589835245958019484noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-53507349656223203052012-09-17T10:06:21.339+01:002012-09-17T10:06:21.339+01:00This looks cool! But I have a concern, let's s...This looks cool! But I have a concern, let's say you have your object and your builder in place, then your object needs to add one more required property, so you have to modify your builder to include a step for that property, and this step should be one of the first steps in your builder call chain -> it will break all the client code of your builder which is used to set some non-required properties (because those steps are usually the last steps in the call chain)<br />Any idea on that?Trương Xuân Tínhhttps://www.blogger.com/profile/06494927095356964880noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-81313780698820249022012-09-15T09:34:51.438+01:002012-09-15T09:34:51.438+01:00Thanks Paul,
This pattern can be implemented with...Thanks Paul,<br /><br />This pattern can be implemented with inner classes and no interfaces as well (the original version was like this) and you implement the step logic straight into each inner class.<br />Are both valid ways, but I think this is a bit more clean.<br /><br />Marcomarcocasthttps://www.blogger.com/profile/09589835245958019484noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-25593435180749336072012-09-14T19:22:01.194+01:002012-09-14T19:22:01.194+01:00Hi Marco,
I had implemented a step builder based...Hi Marco, <br /><br />I had implemented a step builder based around inner classes and interfaces, but your implementation is cleaner and would make for easier maintenance of the builder than my effort.<br /><br />Good stuff & thanks for sharing<br />Paulpjbarfordhttps://www.blogger.com/profile/08365776374516988156noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-54794454467526429682012-09-12T12:51:39.574+01:002012-09-12T12:51:39.574+01:00I will actually change the implementation of Panin...I will actually change the implementation of PaninoStepBuilder using your idea! marcocasthttps://www.blogger.com/profile/09589835245958019484noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-3120397180780125532012-09-12T12:14:11.931+01:002012-09-12T12:14:11.931+01:00I like it. It cleans the whole steps definition. W...I like it. It cleans the whole steps definition. Well though. marcocasthttps://www.blogger.com/profile/09589835245958019484noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-12525736418463045102012-09-12T10:30:14.801+01:002012-09-12T10:30:14.801+01:00Hi Marco,
thanks very much! I just thought of a s...Hi Marco,<br /><br />thanks very much! I just thought of a slight variation of your pattern, which eliminates the need to instantiate a new object for each step. It uses interfaces for the steps, and has one class that implements all step-interfaces. As in your code, the "setter"-methods on the builder return the step-type, exposing only the methods valid for the current step:<br /><br /><a href="http://pastebin.com/AGd3pTR4" rel="nofollow">http://pastebin.com/AGd3pTR4</a><br /><br />Any thoughts on this?<br /><br />Cheers,<br />Martin<br /><br />PS: A first version of the eclipse plugin can be found <a href="https://github.com/belowm/de.below.bgen/downloads" rel="nofollow">here</a>, but it does not include your extension to the pattern yet.<br />Anonymoushttps://www.blogger.com/profile/02578544478168950957noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-60249377398235395342012-09-12T09:45:52.955+01:002012-09-12T09:45:52.955+01:00Hey Martin, thanks for the comment.
Yes, you got ...Hey Martin, thanks for the comment. <br />Yes, you got it right, with this pattern you can completely guide the user in building the object as it should be. <br />Go ahead, develop the plugin and let me know if you need help and when it's finished.<br /><br />Marco<br />marcocasthttps://www.blogger.com/profile/09589835245958019484noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-37878642392569175072012-09-12T09:35:57.886+01:002012-09-12T09:35:57.886+01:00Very clever extension to the builder pattern!
If...Very clever extension to the builder pattern! <br /><br />If I got it right, this basically adds two major benefits to the original pattern:<br /><br /> - forces the client to set mandatory parameters<br /> - avoids invariants when only one property within a set of properties must be set<br /><br />I have written an eclipse plugin for automatically generating builders (http://mbelow.blogspot.de/2012/09/eclipse-plugin-for-creating-builders.html) and I would love to integrate your ideas if you don't mind.<br />Anonymoushttps://www.blogger.com/profile/02578544478168950957noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-74923855109701615572012-08-20T13:23:55.534+01:002012-08-20T13:23:55.534+01:00Indeed its cool pattern and also mentioned by Josh...Indeed its cool pattern and also mentioned by Joshua Bloach in Effective Java. I have also shared one example on my post <a href="http://javarevisited.blogspot.com/2012/06/builder-design-pattern-in-java-example.html" rel="nofollow">What is Builder Pattern in Java</a>, you may find useful.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-83738396286833069392012-07-30T10:39:04.742+01:002012-07-30T10:39:04.742+01:00I like this improvement over the builder pattern, ...I like this improvement over the builder pattern, it might even make people think about the object oriented-ness of the objects they are building as there is a natural relationship between steps and objectsAnonymoushttps://www.blogger.com/profile/06617380794127685471noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-53368516362574947602012-07-29T22:46:06.193+01:002012-07-29T22:46:06.193+01:00This is a great idea. There is nothing worse than ...This is a great idea. There is nothing worse than working on an API where you may not have access to the source code and you have to go back and forth compiling and running the program until you know the minimum amount of parameters you can get away with.Jkhttps://www.blogger.com/profile/10829136547925818953noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-8197196858188669302012-07-29T20:46:09.404+01:002012-07-29T20:46:09.404+01:00It is a cool pattern, i like it.
I am sure it can...It is a cool pattern, i like it. <br />I am sure it can become handy in a wide range of scenarios where: <br /><br />-The order of execution of the steps must be predefined and preserved at all time(Steps cannot be skipped).<br /><br />-A minimum requirements for the object you want to build must be set strictly.(build() cannot be called until the last step is executed).<br /><br />Definitely this is a good to have in my pocket swiss knife :)<br />Good Work!Djordjehttps://www.blogger.com/profile/05544905610992785433noreply@blogger.comtag:blogger.com,1999:blog-6243670623010502252.post-10628245299507737452012-07-28T19:14:29.920+01:002012-07-28T19:14:29.920+01:00Nice article, well done! It offers a way to better...Nice article, well done! It offers a way to better communicate to the final programmer "what" is required to build a complex object and not "how", because the "how" is driven by who really has got the knowledge of the object, and that would be the designer of the Step-Builder itself!Anonymousnoreply@blogger.com