Skip to content

Commit af5d0ec

Browse files
authored
Add example of chain builders with tests (#39)
1 parent ce79cbd commit af5d0ec

File tree

7 files changed

+339
-0
lines changed

7 files changed

+339
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package pl.mperor.lab.java.design.pattern.creational.builder.chain.inner;
2+
3+
import java.util.concurrent.atomic.AtomicInteger;
4+
5+
public class Task {
6+
7+
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(1);
8+
9+
private int id;
10+
private String description;
11+
private boolean done;
12+
13+
private Task() {
14+
}
15+
16+
private Task(Task task) {
17+
this.id = ID_GENERATOR.getAndIncrement();
18+
// Deep copy is required here!
19+
this.description = task.description;
20+
this.done = task.done;
21+
}
22+
23+
public int getId() {
24+
return id;
25+
}
26+
27+
public String getDescription() {
28+
return description;
29+
}
30+
31+
public boolean isDone() {
32+
return done;
33+
}
34+
35+
public static Builder builder() {
36+
return new Task().new Builder();
37+
}
38+
39+
public class Builder {
40+
41+
private Builder() {
42+
}
43+
44+
public Builder description(String description) {
45+
Task.this.description = description;
46+
return this;
47+
}
48+
49+
public Builder done(boolean done) {
50+
Task.this.done = done;
51+
return this;
52+
}
53+
54+
public Task build() {
55+
return new Task(Task.this);
56+
}
57+
}
58+
59+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package pl.mperor.lab.java.design.pattern.creational.builder.chain.nested;
2+
3+
import java.util.concurrent.atomic.AtomicInteger;
4+
5+
public class User {
6+
7+
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(1);
8+
9+
private int id;
10+
private String name;
11+
private String password;
12+
private String email;
13+
14+
private User() {
15+
}
16+
17+
private User(User user) {
18+
this.id = ID_GENERATOR.getAndIncrement();
19+
// Deep copy is required here!
20+
this.name = user.name;
21+
this.password = user.password;
22+
this.email = user.email;
23+
}
24+
25+
int getId() {
26+
return id;
27+
}
28+
29+
public String getName() {
30+
return name;
31+
}
32+
33+
public String getPassword() {
34+
return password;
35+
}
36+
37+
public String getEmail() {
38+
return email;
39+
}
40+
41+
public static Builder builder() {
42+
return new Builder();
43+
}
44+
45+
public static class Builder {
46+
47+
private final User user;
48+
49+
private Builder() {
50+
this.user = new User();
51+
}
52+
53+
public Builder name(String name) {
54+
this.user.name = name;
55+
return this;
56+
}
57+
58+
public Builder password(String password) {
59+
user.password = password;
60+
return this;
61+
}
62+
63+
public Builder email(String email) {
64+
user.email = email;
65+
return this;
66+
}
67+
68+
public User build() {
69+
return new User(user);
70+
}
71+
}
72+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package pl.mperor.lab.java.design.pattern.creational.builder.chain.outer;
2+
3+
import java.time.LocalDate;
4+
5+
public class Person {
6+
7+
private final String firstName;
8+
private final String lastName;
9+
private final LocalDate dateOfBirth;
10+
private final String address;
11+
12+
private Person(PersonBuilder builder) {
13+
this.firstName = builder.getFirstName();
14+
this.lastName = builder.getLastName();
15+
this.dateOfBirth = builder.getDateOfBirth();
16+
this.address = builder.getAddress();
17+
}
18+
19+
public String getFirstName() {
20+
return firstName;
21+
}
22+
23+
public String getLastName() {
24+
return lastName;
25+
}
26+
27+
public LocalDate getDateOfBirth() {
28+
return dateOfBirth;
29+
}
30+
31+
public String getAddress() {
32+
return address;
33+
}
34+
35+
public static Person build(PersonBuilder builder) {
36+
return new Person(builder);
37+
}
38+
39+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package pl.mperor.lab.java.design.pattern.creational.builder.chain.outer;
2+
3+
import java.time.LocalDate;
4+
5+
public class PersonBuilder {
6+
7+
private String firstName;
8+
private String lastName;
9+
private LocalDate dateOfBirth;
10+
private String address;
11+
12+
public PersonBuilder firstName(String name) {
13+
this.firstName = name;
14+
return this;
15+
}
16+
17+
public PersonBuilder lastName(String name) {
18+
this.lastName = name;
19+
return this;
20+
}
21+
22+
public PersonBuilder dateOfBirth(LocalDate date) {
23+
this.dateOfBirth = date;
24+
return this;
25+
}
26+
27+
public PersonBuilder address(String address) {
28+
this.address = address;
29+
return this;
30+
}
31+
32+
public String getFirstName() {
33+
return firstName;
34+
}
35+
36+
public String getLastName() {
37+
return lastName;
38+
}
39+
40+
public LocalDate getDateOfBirth() {
41+
return dateOfBirth;
42+
}
43+
44+
public String getAddress() {
45+
return address;
46+
}
47+
48+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package pl.mperor.lab.java.design.pattern.creational.builder.chain.inner;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.Test;
5+
6+
public class TaskInnerBuilderTest {
7+
8+
@Test
9+
public void builderShouldAllowToBuildTask() {
10+
Task task = Task.builder()
11+
.build();
12+
13+
Assertions.assertNotNull(task);
14+
Assertions.assertTrue(task.getId() >= 1);
15+
Assertions.assertNull(task.getDescription());
16+
Assertions.assertFalse(task.isDone());
17+
}
18+
19+
@Test
20+
public void builderShouldAllowToBuildDoneTasks() {
21+
var builder = Task.builder()
22+
.done(true);
23+
24+
Task t1 = builder
25+
.description("First task")
26+
.build();
27+
28+
Task t2 = builder
29+
.description("Second task")
30+
.build();
31+
32+
Assertions.assertEquals("First task", t1.getDescription());
33+
Assertions.assertEquals("Second task", t2.getDescription());
34+
Assertions.assertTrue(t1.isDone() && t2.isDone());
35+
Assertions.assertNotEquals(t1.getId(), t2.getId());
36+
}
37+
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package pl.mperor.lab.java.design.pattern.creational.builder.chain.nested;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.Test;
5+
6+
public class UserNestedStaticBuilderTest {
7+
8+
@Test
9+
public void userBuilderShouldAllowToBuildUser() {
10+
User user = User.builder().build();
11+
Assertions.assertNotNull(user);
12+
Assertions.assertTrue(user.getId() >= 1);
13+
Assertions.assertNull(user.getName());
14+
Assertions.assertNull(user.getPassword());
15+
}
16+
17+
@Test
18+
public void userBuilderShouldAllowToBuildCustomUser() {
19+
User custom = User.builder()
20+
.name("user")
21+
.password("{noop}password")
22+
23+
.build();
24+
25+
Assertions.assertTrue(custom.getId() >= 1);
26+
Assertions.assertEquals("user", custom.getName());
27+
Assertions.assertNotNull(custom.getPassword());
28+
Assertions.assertEquals("[email protected]", custom.getEmail());
29+
}
30+
31+
@Test
32+
public void userBuilderShouldAllowToBuildGroupOfUsers() {
33+
var builder = User.builder();
34+
User u1 = builder
35+
.name("Anonymous")
36+
37+
.build();
38+
Assertions.assertEquals("Anonymous", u1.getName());
39+
Assertions.assertEquals("[email protected]", u1.getEmail());
40+
41+
User u2 = builder
42+
43+
.build();
44+
Assertions.assertEquals("Anonymous", u2.getName());
45+
Assertions.assertEquals("[email protected]", u2.getEmail());
46+
47+
User u3 = User.builder()
48+
49+
.build();
50+
Assertions.assertNull(u3.getName());
51+
Assertions.assertEquals("[email protected]", u3.getEmail());
52+
53+
Assertions.assertTrue(u1.getId() < u2.getId() && u2.getId() < u3.getId());
54+
}
55+
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package pl.mperor.lab.java.design.pattern.creational.builder.chain.outer;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.time.LocalDate;
7+
import java.time.Month;
8+
9+
public class PersonOuterBuilderTest {
10+
11+
@Test
12+
public void personShouldBeCreatedByPersonBuilder() {
13+
Person person = Person.build(new PersonBuilder()
14+
.firstName("Jack")
15+
.lastName("Bell")
16+
.address("New York")
17+
.dateOfBirth(LocalDate.of(1990, Month.JANUARY, 1)));
18+
19+
Assertions.assertNotNull(person);
20+
Assertions.assertEquals("Jack", person.getFirstName());
21+
Assertions.assertEquals("Bell", person.getLastName());
22+
Assertions.assertEquals("New York", person.getAddress());
23+
Assertions.assertEquals("1990-01-01", person.getDateOfBirth().toString());
24+
}
25+
26+
27+
}

0 commit comments

Comments
 (0)