If I have a constructor for an immutable object that requires several (4+ parameters), is having a single constructor with all the required parameters the correct approach?
I feel this becomes a candidate for the Builder pattern, but I also feel like shying away from it since the parameters are required, and a Builder seems more appropriate when you get to pick and choose.
The example in my mind is a model object that does not change once created.
If you want to create an immutable object, you have to provide a constructor with all necessary fields.
You cannot set the state partially as later you would have to add some notion of "setters" which would by definition add mutability.
Builder pattern is really about partial object building.
Both options have their drawbacks, as you suggest. A four argument constructor is hard to use correctly and makes the code hard to read. However, it communicates the intent that all parameters are mandatory.
A builder would be easier to use and make the code easier to read, but communicate the intent that the arguments are optional.
Since code is more often read than written, I recommend to use the option that promotes readability in this case. Go for a builder and make sure that all paramters are validated when the build() method is called to fail as fast as possible when using the builder incorrectly. Use javadoc to assist with communicating that all parameters are mandatory.
Related
Is there any way to customise the accessor strategy used in clojure.java.data/from-java? from-java is part of the java.data function lib.
I recently updated a third-pary Java-library that used to follow the JavaBean get and set pattern. However, after the update they went from getProperty() to property()...
I guess this change renders the from-java function not suitable in this case, no surprise since the objects are no longer proper JavaBeans.
Is there any way of making from-java aware of this accessor-pattern, or are there any other recursive mapping-mechanisms that supports this?
from-java is a multimethod, do you can override it for any class you like. There is no mechanism for teaching it an alternate naming convention (and if there were such a mechanism, I imagine it would have trouble with "every method with any name at all represents a property"). Therefore you'll have to write manual conversions, but at least the recursion will be handled for you.
It seems you will have to extend the multimethod to support the classes yourself, however, you can probably use reflection (slow, I know) to build something very generic:
For a given object instance, find its class, then the class' DeclaredFields, and from each fields get their name and type
For the same instance, use .getDeclaredMethod or .getDeclaredMethods to find methods for the given name that take no params (use an empty array for this). Those methods should be the new "getters" and you can call these in your instance to extract the values.
Use the Cognitect aws-api instead :)
In code I found:
String age = null;
String place = null;
new Employee(firstParam, secondParam, null, null, age, place);
Class Employee is not our class, probably generated from wsdl file where parameters(age and place) are called alter, platz so someone tried to name null parameters to know which is which but is it good practice? Another problem is that age and place are translated while other two parameters are just null but beside of that is creating variable with null value just to pass it in next line to constructor is okey?
In my experience, when I have pregenerated class defs that expose contracts that don't suit my needs, I tend to abstract them behind a factory method (may not be a full fledged builder, but depends..) and expose overloaded contracts that help API users to simply pass whatever args are actually needed. Now as to whether naming variables as null is considered good practice or not, i think that is more subjective of your choice rather than an established pattern. But IMO, simply passing null would be cleaner than writing few extra lines only to pass method args.
There is no clear yes or no on this pattern. It is indeed commonly used in some areas.
It has the obvious advantage that it introduces the naming and by that making your code easier to read and maintain, which is always good and also reduces likelyness of bugs.
But it also has disadvantages. The biggest is probably that, for a reader, the intend of the variable may not be directly clear. Tripping into thinking that it might be used later on, thus polluting your variable scope. It might also just not be very convenient if you employ this pattern all the time.
Without going into much detail, there are some other solutions to it:
Most IDEs have a feature called parameter-hints
Some languages, like Kotlin have named-parameters
A builder pattern for the method-call would introduce explicit naming
Redesign the method to not allow optional null-parameters (some consider optional-parameters a bad practice)
Get rid of optional parameters by overloading your method
Apart from that, the question is probably too opinion-based for StackOverflow, especially since there is not really a strong opinion on this pattern in the community.
No, it is not a good practice to do something like this. Anyway, when you're declaring some fields like this String age; , age will be null by default. Instead I would suggest to look over some generic builder patterns (look at #SpaceTrucker 's answer please) instead of instantiating by constructors with more than 2 parameters.
I have a class named ActivityLog. This class holds a list of ActivityRecords. I want to return a list of ActivityRecords by these criterias: Environment and Condition. Should the method name include the "criteria"? See example:
activityLog.allRecords();
activityLog.allRecordsBy(Environment environment);
activityLog.allRecordsBy(Condition condition);
activityLog.allRecordsBy(Condition condition, Environment environment);
or
activityLog.allRecordsByEnvironment(Environment environment);
activityLog.allRecordsByCondtion(Condition condition);
I probably think the first is better because you will read the method name and you will understand from the parameter what it does, but I may be wrong? Which is the best, or are there even better alternatives?
I could have named the methods records(), recordsBy etc. too, but I want to have a consitency through my API where you always start writing all for lists of objects so you get help from for example Intelli Sense.
I like putting the criteria in the actual method name. So I would use:
activityLog.allRecordsByEnvironment(Environment environment);
To me proper method naming expresses a small summary of what the method does. Since the parameters are included in the method signature I would not consider the parameters to be part of the actual name, therefore not placing the criteria in the name gives the user of an api incomplete information about the methods functionality. (IMO)
I applaud your effort to practice self documenting code, great practice.
I like the overloaded variant (your first example), because it communicates that the methods are all related and provide largely the same functionality, aka, you are returning records, filtered by some criteria. You will see examples of this in many open source libraries and even the SDK itself.
I'd treat it the same as static factory methods, which are named constructors. And there not only parameter says what this method does, its name itself does it. So I'd choose 2nd option.
#Bob, about names being too long - even if you would put 2 parameters into its name, it still would be ok for me. Anyway you should avoid having methods with more than 3 parameters. Following this rule will prevent your methods' names from being enormous long.
I would take the first one.
If these methods are doing the same thing or providing the same functionality then they should have the same name. But be aware of Effective Java Item 41 and 42. You've to ensure that at least one corresponding param of overloaded method are having radically different types.
The 2nd approach becomes ugly very fast with every param added. I see this in often in Broker classes at work. There are people writing methods like findByFirstnameAndLastnameAndBirthdayOrderByUgliness(blablub). No comment.
Methods in OOP represent behavior, so I would name all of them getRecords() and made them overloaded.
In my opinion, specifying criteria in the name of method looks like naming heirarchy classes like this
Car -> BMW_Car -> X5_BMW_Car
I need to create an email-notification service (as a part of a bigger project).
It will be used to send several types of notification messages which are based on html-templates.
I can design it in two ways:
The first way is based on the builder pattern. It's universal (as I think) and can handle all necessary cases. But it's not very convenient for those who will use it. The typical usage would look like this:
messageBuilder
.put("name", "John Doe")
.put("company", companyObj)
.processPattern(pattern)
.send(addresses, subject);
The second way is to implement all cases explicitly. It means that usage code (shown below) will be as simple as possible but we'll have to modify API (add new methods) every time when we need to handle any new case.
messageSender.sendPersonExpenceNotification(addresses, "John Doe", company);
Which one is better? Why? (the language is Java if it matters)
Thanks!
I think the answer is to use both. I would suggest using the more generic approach (the message builder) in the API and then providing client-side convenience functions/classes that are simple to use for specific tasks. This way the API doesn't have to update when you add new cases but the client can still use the most direct call for what they're trying to do.
Effective Java 2nd Edition, Item 2: Consider a builder when faced with many constructor parameters.
The builder pattern is more readable, especially as you have potentially many more parameters. That said, it's usually more common to have specific setName, setCompany, etc methods for a builder. That way you can also enforce type-safety, e.g. setSomeBoolean(boolean), setSomeInt(int), etc.
A builder pattern also allows you to set default values to some parameters, and user can conveniently override the default on some parameters. Providing methods to simulate this involves writing many overloads, which exacerbate the problem further.
Related questions
When would you use the Builder Pattern?
Nowadays, the most favored design pattern relies upon "fluent" builder. This way, you gain the genericity of the builder, with an understandable interface.
Implementing it is rather mundane, considering it's only a matter of well choosing your method names.
Good real world examples are all the FEST* libraries.
How can i get hold of the instantiating object from a constructor in java?
I want to store reference to the parent object for some GUI classes to simulate event bubbling - calling parents handlers - but i dont wanna change all the existing code.
Short answer: there isn't a way to do this in Java. (You can find out what class called you, but the long answer below applies there for the most part as well.)
Long answer: Code that magically behaves differently depending on where it's being invoked from is almost always a bad idea. It's confusing to whoever has to maintain your code, and it seriously hurts your ability to refactor. For example, suppose you realize that two of the places instantiating your object have basicaly the same logic, so you decide to factor out the common bits. Surprise! Now the code behaves differently because it's being instantiated from somewhere else. Just add the parameter and fix the callers. It'll save you time in the long run.
If you want to know the invoking class, then pass "this" as a parameter to the constructor.
Thing thing = new Thing(this);
Edit: A modern IDE allowing refactoring will make this very easy to do.
Intercepting method calls (including constructors) without changing a ton of existing code is one thing Aspect-oriented programming was made for.
Check out AspectJ for a start.
With AspectJ, you can define a "pointcut" that specifies that you want to intercept constructor calls for a certain object or set of objects (using wildcards if need be), and within the interception code ("advice"), you will be given method context, which includes information about the both the calling method and object.
You can even use AspectJ to add fields to your object's to store the parent reference without modifying their existing code (this is called "introduction").