diff --git a/monad/index.md b/monad/index.md
new file mode 100644
index 000000000..a11360a2e
--- /dev/null
+++ b/monad/index.md
@@ -0,0 +1,29 @@
+---
+layout: pattern
+title: Monad
+folder: monad
+permalink: /patterns/monad/
+categories: Presentation Tier
+tags:
+ - Java
+ - Difficulty-Advanced
+---
+
+## Intent
+
+Monad pattern based on monad from linear algebra represents the way of chaining operations
+together step by step. Binding functions can be described as passing one's output to another's input
+basing on the 'same type' contract.
+
+
+
+## Applicability
+
+Use the Monad in any of the following situations
+
+* when you want to chain operations easily
+* when you want to apply each function regardless of the result of any of them
+
+## Credits
+* [Design Pattern Reloaded by Remi Forax](https://youtu.be/-k2X7guaArU)
+* [Brian Beckman: Don't fear the Monad](https://channel9.msdn.com/Shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads)
diff --git a/monad/pom.xml b/monad/pom.xml
new file mode 100644
index 000000000..ec5a14a8c
--- /dev/null
+++ b/monad/pom.xml
@@ -0,0 +1,43 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.11.0-SNAPSHOT
+
+ monad
+
+
+ junit
+ junit
+ test
+
+
+
+
diff --git a/monad/src/main/java/com/iluwatar/monad/App.java b/monad/src/main/java/com/iluwatar/monad/App.java
new file mode 100644
index 000000000..2ab376201
--- /dev/null
+++ b/monad/src/main/java/com/iluwatar/monad/App.java
@@ -0,0 +1,19 @@
+package com.iluwatar.monad;
+
+import java.util.Objects;
+
+public class App {
+
+ /**
+ * Program entry point.
+ *
+ * @param args @param args command line args
+ */
+ public static void main(String[] args) {
+ User user = new User("user", 24, Sex.FEMALE, "foobar.com");
+ System.out.println(Validator.of(user).validate(User::getName, Objects::nonNull, "name is null")
+ .validate(User::getName, name -> !name.isEmpty(), "name is empty")
+ .validate(User::getEmail, email -> !email.contains("@"), "email doesn't containt '@'")
+ .validate(User::getAge, age -> age > 20 && age < 30, "age isn't between...").get().toString());
+ }
+}
diff --git a/monad/src/main/java/com/iluwatar/monad/Sex.java b/monad/src/main/java/com/iluwatar/monad/Sex.java
new file mode 100644
index 000000000..8b7e43f3c
--- /dev/null
+++ b/monad/src/main/java/com/iluwatar/monad/Sex.java
@@ -0,0 +1,5 @@
+package com.iluwatar.monad;
+
+public enum Sex {
+ MALE, FEMALE
+}
diff --git a/monad/src/main/java/com/iluwatar/monad/User.java b/monad/src/main/java/com/iluwatar/monad/User.java
new file mode 100644
index 000000000..de1be5a45
--- /dev/null
+++ b/monad/src/main/java/com/iluwatar/monad/User.java
@@ -0,0 +1,39 @@
+package com.iluwatar.monad;
+
+public class User {
+
+ private String name;
+ private int age;
+ private Sex sex;
+ private String email;
+
+ /**
+ *
+ * @param name - name
+ * @param age - age
+ * @param sex - sex
+ * @param email - email
+ */
+ public User(String name, int age, Sex sex, String email) {
+ this.name = name;
+ this.age = age;
+ this.sex = sex;
+ this.email = email;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public Sex getSex() {
+ return sex;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+}
diff --git a/monad/src/main/java/com/iluwatar/monad/Validator.java b/monad/src/main/java/com/iluwatar/monad/Validator.java
new file mode 100644
index 000000000..7cc84298d
--- /dev/null
+++ b/monad/src/main/java/com/iluwatar/monad/Validator.java
@@ -0,0 +1,81 @@
+package com.iluwatar.monad;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Class representing Monad design pattern. Monad is a way of chaining operations on the
+ * given object together step by step. In Validator each step results in either success or
+ * failure indicator, giving a way of receiving each of them easily and finally getting
+ * validated object or list of exceptions.
+ * @param Placeholder for an object.
+ */
+public class Validator {
+ private final T t;
+ private final List exceptions = new ArrayList<>();
+
+ /**
+ * @param t object to be validated
+ */
+ private Validator(T t) {
+ this.t = t;
+ }
+
+ /**
+ * Creates validator against given object
+ *
+ * @param t object to be validated
+ * @param object's type
+ * @return new instance of a validator
+ */
+ public static Validator of(T t) {
+ return new Validator<>(Objects.requireNonNull(t));
+ }
+
+ /**
+ * @param validation one argument boolean-valued function that
+ * represents one step of validation. Adds exception to main validation exception
+ * list when single step validation ends with failure.
+ * @param message error message when object is invalid
+ * @return this
+ */
+ public Validator validate(Predicate validation, String message) {
+ if (!validation.test(t)) {
+ exceptions.add(new IllegalStateException(message));
+ }
+ return this;
+ }
+
+ /**
+ * Extension for the {@link Validator#validate(Function, Predicate, String)} method,
+ * dedicated for objects, that need to be projected before requested validation.
+ * @param projection function that gets an objects, and returns projection representing
+ * element to be validated.
+ * @param validation see {@link Validator#validate(Function, Predicate, String)}
+ * @param message see {@link Validator#validate(Function, Predicate, String)}
+ * @param see {@link Validator#validate(Function, Predicate, String)}
+ * @return this
+ */
+ public Validator validate(Function projection, Predicate validation,
+ String message) {
+ return validate(projection.andThen(validation::test)::apply, message);
+ }
+
+ /**
+ * To receive validated object.
+ *
+ * @return object that was validated
+ * @throws IllegalStateException when any validation step results with failure
+ */
+ public T get() throws IllegalStateException {
+ if (exceptions.isEmpty()) {
+ return t;
+ }
+ IllegalStateException e = new IllegalStateException();
+ exceptions.forEach(e::addSuppressed);
+ throw e;
+ }
+}
diff --git a/monad/src/test/java/com/iluwatar/monad/AppTest.java b/monad/src/test/java/com/iluwatar/monad/AppTest.java
new file mode 100644
index 000000000..5d23b41a6
--- /dev/null
+++ b/monad/src/test/java/com/iluwatar/monad/AppTest.java
@@ -0,0 +1,13 @@
+package com.iluwatar.monad;
+
+import org.junit.Test;
+
+public class AppTest {
+
+ @Test
+ public void testMain() {
+ String[] args = {};
+ App.main(args);
+ }
+
+}
diff --git a/monad/src/test/java/com/iluwatar/monad/MonadTest.java b/monad/src/test/java/com/iluwatar/monad/MonadTest.java
new file mode 100644
index 000000000..5ef2ecc69
--- /dev/null
+++ b/monad/src/test/java/com/iluwatar/monad/MonadTest.java
@@ -0,0 +1,42 @@
+package com.iluwatar.monad;
+
+
+import junit.framework.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.Objects;
+
+public class MonadTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testForInvalidName() {
+ thrown.expect(IllegalStateException.class);
+ User tom = new User(null, 21, Sex.MALE, "tom@foo.bar");
+ Validator.of(tom).validate(User::getName, Objects::nonNull, "name cannot be null").get();
+ }
+
+ @Test
+ public void testForInvalidAge() {
+ thrown.expect(IllegalStateException.class);
+ User tom = new User("John", 17, Sex.MALE, "john@qwe.bar");
+ Validator.of(tom).validate(User::getName, Objects::nonNull, "name cannot be null")
+ .validate(User::getAge, age -> age > 21, "user is underaged")
+ .get();
+ }
+
+ @Test
+ public void testForValid() {
+ User tom = new User("Sarah", 42, Sex.FEMALE, "sarah@det.org");
+ User validated = Validator.of(tom).validate(User::getName, Objects::nonNull, "name cannot be null")
+ .validate(User::getAge, age -> age > 21, "user is underaged")
+ .validate(User::getSex, sex -> sex == Sex.FEMALE, "user is not female")
+ .validate(User::getEmail, email -> email.contains("@"), "email does not contain @ sign")
+ .get();
+ Assert.assertSame(validated, tom);
+ }
+}
diff --git a/pom.xml b/pom.xml
index c15ca20cf..0b587fd06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -121,6 +121,7 @@
event-driven-architecture
feature-toggle
value-object
+ monad