diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/HtmlDocument.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/HtmlDocument.java
new file mode 100644
index 0000000000..db0f988908
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/HtmlDocument.java
@@ -0,0 +1,46 @@
+package com.baeldung.fluentinterface;
+
+import static java.util.Arrays.stream;
+import static java.util.stream.Collectors.joining;
+
+public class HtmlDocument {
+ private final String content;
+
+ private HtmlDocument(String html) {
+ this.content = html;
+ }
+
+ public HtmlDocument() {
+ this("");
+ }
+
+ public String html() {
+ return String.format("%s", content);
+ }
+
+ public HtmlDocument header(String header) {
+ return new HtmlDocument(String.format("%s
%s
", content, header));
+ }
+
+ public HtmlDocument secondaryHeader(String header) {
+ return new HtmlDocument(String.format("%s %s
", content, header));
+ }
+
+ public HtmlDocument paragraph(String paragraph) {
+ return new HtmlDocument(String.format("%s %s
", content, paragraph));
+ }
+
+ public HtmlDocument horizontalLine() {
+ return new HtmlDocument(String.format("%s
", content));
+ }
+
+ public HtmlDocument orderedList(String... items) {
+ String listItems = stream(items).map(el -> String.format("%s", el)).collect(joining());
+ return new HtmlDocument(String.format("%s %s
", content, listItems));
+ }
+
+ public HtmlDocument unorderedList(String... items) {
+ String listItems = stream(items).map(el -> String.format("%s", el)).collect(joining());
+ return new HtmlDocument(String.format("%s ", content, listItems));
+ }
+}
\ No newline at end of file
diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/LargeHtmlDocument.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/LargeHtmlDocument.java
new file mode 100644
index 0000000000..fff8c97b5b
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/LargeHtmlDocument.java
@@ -0,0 +1,40 @@
+package com.baeldung.fluentinterface;
+
+import com.baeldung.fluentinterface.components.HtmlElement;
+import com.baeldung.fluentinterface.components.HtmlHeader;
+import com.baeldung.fluentinterface.components.HtmlList;
+
+import static java.lang.String.format;
+import static java.util.Arrays.stream;
+import static java.util.stream.Collectors.joining;
+
+public class LargeHtmlDocument {
+ private final String content;
+
+ private LargeHtmlDocument(String html) {
+ this.content = html;
+ }
+
+ public LargeHtmlDocument() {
+ this("");
+ }
+
+ public String html() {
+ return format("%s", content);
+ }
+
+ public LargeHtmlDocument head(HtmlElement head) {
+ return new LargeHtmlDocument(format("%s %s", content, head.html()));
+ }
+ public LargeHtmlDocument body(HtmlElement body) {
+ return new LargeHtmlDocument(format("%s %s", content, body.html()));
+ }
+ public LargeHtmlDocument footer(HtmlElement footer) {
+ return new LargeHtmlDocument(format("%s ", content, footer.html()));
+ }
+
+ private LargeHtmlDocument append(String html) {
+ return new LargeHtmlDocument(format("%s %s", content, html));
+ }
+
+}
\ No newline at end of file
diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/User.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/User.java
new file mode 100644
index 0000000000..1606369c26
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/User.java
@@ -0,0 +1,65 @@
+package com.baeldung.fluentinterface;
+
+public class User {
+ private String firstName;
+ private String lastName;
+ private String email;
+ private String username;
+ private Long id;
+
+ public String name() {
+ return firstName + " " + lastName;
+ }
+
+ public User(String firstName, String lastName, String email, String username, Long id) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.email = email;
+ this.username = username;
+ this.id = id;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String firstName;
+ private String lastName;
+ private String email;
+ private String username;
+ private Long id;
+
+ private Builder() {
+ }
+
+ public Builder firstName(String firstName) {
+ this.firstName = firstName;
+ return this;
+ }
+
+ public Builder lastName(String lastName) {
+ this.lastName = lastName;
+ return this;
+ }
+
+ public Builder email(String email) {
+ this.email = email;
+ return this;
+ }
+
+ public Builder username(String username) {
+ this.username = username;
+ return this;
+ }
+
+ public Builder id(Long id) {
+ this.id = id;
+ return this;
+ }
+
+ public User build() {
+ return new User(firstName, lastName, email, username, id);
+ }
+ }
+}
diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HorizontalLine.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HorizontalLine.java
new file mode 100644
index 0000000000..66979b98f9
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HorizontalLine.java
@@ -0,0 +1,8 @@
+package com.baeldung.fluentinterface.components;
+
+public class HorizontalLine implements HtmlElement {
+ @Override
+ public String html() {
+ return "
";
+ }
+}
diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlDiv.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlDiv.java
new file mode 100644
index 0000000000..7625401444
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlDiv.java
@@ -0,0 +1,29 @@
+package com.baeldung.fluentinterface.components;
+
+public class HtmlDiv implements HtmlElement {
+
+ private final String content;
+
+ public HtmlDiv(String content) {
+ this.content = content;
+ }
+
+ public HtmlDiv() {
+ this.content = "";
+ }
+
+ public HtmlDiv append(HtmlElement element) {
+ return new HtmlDiv(content + element.html());
+ }
+ public HtmlDiv text(String text) {
+ return new HtmlDiv(content + text);
+ }
+ public HtmlDiv paragraph(String text) {
+ return new HtmlDiv(content + text);
+ }
+
+ @Override
+ public String html() {
+ return String.format("%s
", content);
+ }
+}
diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlElement.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlElement.java
new file mode 100644
index 0000000000..ff46dc0029
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlElement.java
@@ -0,0 +1,5 @@
+package com.baeldung.fluentinterface.components;
+
+public interface HtmlElement {
+ String html();
+}
diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlHeader.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlHeader.java
new file mode 100644
index 0000000000..12c400014d
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlHeader.java
@@ -0,0 +1,34 @@
+package com.baeldung.fluentinterface.components;
+
+public class HtmlHeader implements HtmlElement {
+
+ private final Type type;
+ private final String value;
+
+ public HtmlHeader(Type type, String value) {
+ this.type = type;
+ this.value = value;
+ }
+
+ @Override
+ public String html() {
+ return String.format("<%s>%s%s>", type.tag(), value, type.tag());
+ }
+
+ public enum Type {
+ PRIMARY("h1"),
+ SECONDARY("h2"),
+ THIRD("h3"),
+ FOURTH("h4");
+
+ private final String tag;
+
+ Type(String tag) {
+ this.tag = tag;
+ }
+
+ public String tag() {
+ return tag;
+ }
+ }
+}
diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlList.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlList.java
new file mode 100644
index 0000000000..030c9aaa5c
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlList.java
@@ -0,0 +1,39 @@
+package com.baeldung.fluentinterface.components;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static java.lang.String.format;
+import static java.util.stream.Collectors.joining;
+
+public class HtmlList implements HtmlElement {
+
+ private final Type type;
+ private final List items;
+
+ public HtmlList(Type type, String... items) {
+ this.type = type;
+ this.items = Arrays.asList(items);
+ }
+
+ @Override
+ public String html() {
+ String listItems = items.stream().map(el -> format("%s", el)).collect(joining());
+ return String.format("<%s>%s%s>", type.tag(), listItems, type.tag());
+ }
+
+ public enum Type {
+ ORDERED("ol"),
+ UNORDERED("ul");
+
+ private final String tag;
+
+ Type(String tag) {
+ this.tag = tag;
+ }
+
+ public String tag() {
+ return tag;
+ }
+ }
+}
diff --git a/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlSpan.java b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlSpan.java
new file mode 100644
index 0000000000..2bdf55eb72
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/main/java/com/baeldung/fluentinterface/components/HtmlSpan.java
@@ -0,0 +1,27 @@
+package com.baeldung.fluentinterface.components;
+
+public class HtmlSpan implements HtmlElement {
+
+ private final String content;
+
+ public HtmlSpan(String content) {
+ this.content = content;
+ }
+
+ public HtmlSpan() {
+ this.content = "";
+ }
+
+ public HtmlSpan append(HtmlElement element) {
+ return new HtmlSpan(content + element.html());
+ }
+
+ public HtmlSpan paragraph(String text) {
+ return new HtmlSpan(content + text);
+ }
+
+ @Override
+ public String html() {
+ return String.format("%s", content);
+ }
+}
diff --git a/patterns-modules/design-patterns-behavioral-2/src/test/java/com/baeldung/fluentinterface/FluentInterfaceUnitTest.java b/patterns-modules/design-patterns-behavioral-2/src/test/java/com/baeldung/fluentinterface/FluentInterfaceUnitTest.java
new file mode 100644
index 0000000000..bf5aadcf13
--- /dev/null
+++ b/patterns-modules/design-patterns-behavioral-2/src/test/java/com/baeldung/fluentinterface/FluentInterfaceUnitTest.java
@@ -0,0 +1,101 @@
+package com.baeldung.fluentinterface;
+
+import com.baeldung.fluentinterface.components.*;
+import com.baeldung.fluentinterface.components.HtmlHeader.Type;
+import org.junit.jupiter.api.Test;
+
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.baeldung.fluentinterface.components.HtmlList.Type.ORDERED;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class FluentInterfaceUnitTest {
+
+ @Test
+ void givenTenNumbers_thenStreamIsProcessedCorrectly() {
+ Stream numbers = Stream.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+ Stream processedNumbers = numbers.distinct()
+ .filter(nr -> nr % 2 == 0)
+ .skip(1)
+ .limit(4)
+ .map(nr -> "#" + nr)
+ .peek(nr -> System.out.println(nr));
+ String result = processedNumbers.collect(Collectors.joining(", "));
+
+ assertThat(result).isEqualTo("#2, #4, #6, #8");
+ }
+
+ @Test
+ void givenUserBuilder_thenCreateUserCorrectly() {
+ User.Builder userBuilder = User.builder();
+ userBuilder = userBuilder
+ .firstName("John")
+ .lastName("Doe")
+ .email("jd@gmail.com")
+ .username("jd_2000")
+ .id(1234L);
+
+ User user = userBuilder.build();
+
+ assertThat(user.name()).isEqualTo("John Doe");
+ }
+
+ @Test
+ void givenHtmlDocument_thenGenerateHtmlCorrectly() {
+ HtmlDocument document = new HtmlDocument()
+ .header("Principles of O.O.P.")
+ .paragraph("OOP in Java.")
+ .horizontalLine()
+ .paragraph("The main pillars of OOP are:")
+ .orderedList("Encapsulation", "Inheritance", "Abstraction", "Polymorphism");
+ String html = document.html();
+
+ assertThat(html).isEqualToIgnoringWhitespace(
+ ""
+ + "Principles of O.O.P.
"
+ + "OOP in Java.
"
+ + "
"
+ + "The main pillars of OOP are:
"
+ + ""
+ + "- Encapsulation
"
+ + "- Inheritance
"
+ + "- Abstraction
"
+ + "- Polymorphism
"
+ + "
"
+ + ""
+ );
+ }
+
+ @Test
+ void givenHtmlDocument_thenInstanceIsImmutable() {
+ HtmlDocument document = new HtmlDocument()
+ .header("Principles of O.O.P.");
+ HtmlDocument updatedDocument = document
+ .paragraph("OOP in Java.");
+
+ assertThat(document).isNotEqualTo(updatedDocument);
+ }
+
+
+ @Test
+ void givenLargeHtmlDocument_thenGenerateHtmlCorrectly() {
+ String html = new LargeHtmlDocument()
+ .head(new HtmlHeader(Type.PRIMARY, "title"))
+ .body(new HtmlDiv()
+ .append(new HtmlSpan()
+ .paragraph("learning OOP from John Doe")
+ .append(new HorizontalLine())
+ .paragraph("The pillars of OOP:")
+ )
+ .append(new HtmlList(ORDERED, "Encapsulation", "Inheritance", "Abstraction", "Polymorphism"))
+ )
+ .footer(new HtmlDiv()
+ .paragraph("trademark John Doe")
+ )
+ .html();
+
+ String expectedHtml = " title
learning OOP from John Doe
The pillars of OOP:- Encapsulation
- Inheritance
- Abstraction
- Polymorphism
";
+ assertThat(html).isEqualToIgnoringWhitespace(expectedHtml);
+ }
+}
\ No newline at end of file