condition based lombok building of objects
Asked Answered
S

3

6

So here is the existing code snippet written to build Humans ( as in matrix movie :) )

if (gender.equals("male")){
    return Human.builder()
        .gender('male')
        .name('abc')
        .speaks("english")
        .alive(true)
        .build();
}else{
    return Human.builder()
        .gender('female')
        .name('abcd')
        .speaks("english")
        .alive(true)
        .build();    
}

If you look, this code has lot of redundancy in attribute assignment which can be minimised. Now imagine 10 conditions like it (here, its just 2!), no matter what you try, it would eventually lead to ugly looking redundant code.

I tried searching lot of resources online and couldn't find any way to build object as per builder design. What i would like to achive here ( to reduce code redundancy) is something like below :

Human human = Human.builder()
            .speaks("english")
            .alive(true);

if (gender.equals("male")){
        human = human    // or just human.gender('male').name('abc'); no assignment
        .gender('male')
        .name('abc');
}else{
        human = human // or just human.gender('female').name('abcd'); no assignment
        .gender('female')
        .name('abcd');
}            
return human.build();

Is this possible via lombok or anyone knows a better way to build objects here?
If its worth it, i am on drop-wizard

Soria answered 30/1, 2018 at 11:28 Comment(5)
Maybe this thread can help you to think in another strategy without Lombok but still using builder: #7303391Multicolor
if (gender == "male")? Really?Ciracirca
@Ciracirca mmmmm....what about it?Soria
if (gender.equals("male")) !Ciracirca
@Ciracirca : haha, TBH, its the least i care about right now. Its a pseudo code anyway with a different problem statement than =. Thanks anyway for pointing out, ill update!Soria
B
7

Use Lombok's Builder:

import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class Human {
    private String name;
    private String gender;
    private String speaks;
    private boolean alive;


    public static void main(String[] args) {
        HumanBuilder humanBuilder = Human.builder();

        String gender = "female";


        humanBuilder
                .speaks("english")
                .alive(true);

        if("male".equals(gender)){
            humanBuilder
                    .gender("male")
                    .name("abc");
        }else{
            humanBuilder
                    .gender("female")
                    .name("abcd");
        }

        Human human = humanBuilder.build();
        System.out.println(human);
    }
}

Result:

Human(name=abcd, gender=female, speaks=english, alive=true)
Beilul answered 30/1, 2018 at 11:41 Comment(4)
Human class will have a lombok.Builder annotation and doing Human.builder(); initially will raise error (have tried it already) . Is there anything i am not understanding??Soria
I tried it too. No initial errors. If you see doc: projectlombok.org/features/Builder you sill see that Human.builder(); is just public static method.Beilul
@DmitryGorkovets : yes i see that. My mistake.I wasn't using Builder method of the class, seems to be working.will work out and accept in due time if all goes well. +1 meanwhile! :)Soria
Yes, my bad, realized that.Beilul
I
4

You can use any of the following ways for removing code redundancy and giving clarity:

OPTION 1:

Human human = Human.builder()
        .gender(gender.equals("M")?"male":(gender.equals("F")?"female":"transgender"))
        .name("abc")
        .speaks("english")
        .alive(true)
        .address(Optional.ofNullable(address).orElse(defaultAddress))
        .build();

OPTION 2:

Human human = Human.builder()
            .gender(getGender(gender))
            .name("abc")
            .speaks("english")
            .alive(true)
            .address(Optional.ofNullable(address).orElse(defaultAddress))
            .build();

public static String getGender(String gender){
   return gender.equals("M")?"male":(gender.equals("F")?"female":"transgender");
}

OPTION 3:

Human.HumanBuilder humanBuilder = Human.builder();
humanBuilder.name("abc").speaks("english").alive(true);
if(gender.equals("M")){
   humanBuilder.gender("male");
}else {
  humanBuilder.gender("female");
}

Human human = humanBuilder.build();

My personal preference is Option 2 as it makes the code more cleaner.

Hope this helps.

Incomprehensible answered 30/1, 2018 at 11:46 Comment(5)
agreed on this one but downside is it would limit me to only 2 condition match. What if there is a 3rd gender - say transgender ?Soria
You can put N number of conditions, it doesn't matter. Please refer the updated answer.Incomprehensible
i see what you did there but question is, is it a solution or a hack ? :)Soria
According to me its a solution. Its not a hack. I am not doing anything wrong , just making the code shorter and cleaner.Incomprehensible
These are good solutions but not as elegant as it would be if support for this was built into Lombok, more specifically in the case where an attribute should only be set if the condition is true the code becomes a bit bulky (see Option 3 above). Would REALLY like if the Lombok team would add this feature.Johst
D
0

I like this pattern - which would allow for skipping values that are not present (e.g. not explicitly given):

Human human = Human.builder()
        .name("abc")
        .speaks("english")
        .alive(true)
        .address(Optional.ofNullable(address).orElse(defaultAddress));
getGender()
    .ifPresent(gender -> 
        human.gender(gender));

human.build();

...

public static Optional<String> getGender(String gender){
   return gender.equals("M")?"male": (gender.equals("F")?"female":"transgender");
}
Damson answered 18/6 at 13:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.