Combinator Pattern

Combinator Pattern

Introduction

The Combinator Pattern is based on the idea of composing functions together to create a more complex result. It uses a set of functions that take in the same type of input and produce the same type of output. These functions are then combined together to form a single, more complex operation.

Combinator Pattern in Java 8

Steps

  1. Make an interface DummyInterface<K,V> which extends Function<K,V>. This interface would be used to create Function which accepts argument K and returns value V

  2. Create static combinator methods (like and, or) in the interface which can combine the results of multiple DummyInterface functions.

  3. Now we can use implementation of DummyInterface<K,V> to create multiple lambda functions. We can also use combinator methods to merge the results of these lambda functions.

For example, consider a case where we want to validate a user using multiple checks. If the user is valid then we return a success message else return a reason for invalidation.

Validator interface:

public interface RegistrationValidatorFunction extends Function<Customer, ValidationResult> {

  // METHODS USED FOR COMBINING THE VALIDATORS
  default RegistrationValidatorFunction and(RegistrationValidatorFunction other) {
    return customer -> {
      ValidationResult result = this.apply(customer);
      return result.equals(SUCCESS) ? other.apply(customer) : result;
    };
  }

  default RegistrationValidatorFunction or(RegistrationValidatorFunction other) {
    return customer -> {
      ValidationResult result = this.apply(customer);
      return result.equals(SUCCESS) ? SUCCESS : other.apply(customer);
    };
  }
}

enum ValidationResult {
  SUCCESS,
  EMAIL_NOT_VALID,
  EMAIL_NOT_GMAIL,
  PHONE_NUMBER_NOT_VALID
}

Driver class:

public class Main {
  public static void main(String[] args) {
    System.out.println(isValidCustomer().apply(new Customer("alice@gmail.com", "2312312"))); // SUCCESS
    System.out.println(isValidCustomer().apply(new Customer("somerandommail", "+02312312")));// SUCCESS
    System.out.println(isValidCustomer().apply(new Customer("alice@ymail.com", "2312312"))); // EMAIL_NOT_GMAIL
    System.out.println(isValidCustomer().apply(new Customer("somerandommail", "2312312")));  // EMAIL_NOT_VALID
  }

//------CREATE VALIDATOR FUNCTIONS BY IMPLEMENTATION OF RegistrationValidatorFunction------//
  static RegistrationValidatorFunction isGmail() {
    return customer -> customer.email.contains("@gmail.com") ? SUCCESS : EMAIL_NOT_GMAIL;
  }

  static RegistrationValidatorFunction isEmailValid() {
    return customer -> customer.email.contains("@") ? SUCCESS: EMAIL_NOT_VALID;
  }

  static RegistrationValidatorFunction isPhoneValid() {
    return customer -> customer.phoneNumber.contains("+0") ? SUCCESS: PHONE_NUMBER_NOT_VALID;
  }

  //------CREATE VALIDATOR METHOD BY COMBINING MULTIPLE OTHER VALIDATOR METHODS------//
  static RegistrationValidatorFunction isValidCustomer() {
    return customer -> isPhoneValid().or(isEmailValid().and(isGmail())).apply(customer);
  }
}