Design patterns are a toolkit of tried and tested solutions to common problems in software design.

It is a common language for everyone to use to communicate ideas more efficiently.

Optional: Patterns and Anti-patterns

  • null is a smell
  • return empty collections or arrays, not nulls

 

What if we have to return a single value?
We can return Optional<T>

public class Sample {
  public static Optional<String> getName() {
    return Optional.empty();
  }
}

 

How to get the value out from the optional?

public class Application {
  Optional<String> result = getName();
  log.info(result.orElse("not found"));
}

 

Avoid doing this. It defeats the purpose of using Optional in the first place, which is to avoid null pointer exceptions.

public class Application {
  Optional<String> result = getName();
  result.get();
}

 

Avoid using Optional as a parameter, Use overloading instead

// not easy to use
public void sendEmail(Optional<String> email) {
}

// client code
sendEmail(Optional.empty());
sendEmail(Optional.of("johndoe@gmail.com"));
// easier to use
public void sendEmail() {
}
public void sendEmail(String email) {
}

// client code
sendEmail();

 

General Guidelines

  • If a method always returns a single value, don’t use Optional
  • If a method may or may not return a single value, then use Optional
  • If the result is a Collection, don’t use Optional, return empty collections
  • Don’t use Optional as a parameter to methods. If needed, use overloading instead.

Factory method using default methods

Factory Method

  • The factory is a method and does not sit in a class
  • Relies on an interface or a derived class to provide the implementation, whereas the base class provides the common behaviour
interface Pet {}
class Dog implements Pet {}
class Cat implements Pet {}

interface Person {
  // interface have no state
  // private Pet pet;
  Pet getPet();
  
  default void play() {
    log.info("playing with " + getPet());
  }
}

class DogLover implements Person {
  private Dog dog = new Dog();

  public Pet getPet() { 
    return dog; 
  }
}

Execute around method Pattern

Suppose we have some resource and we need to release it after calling some methods on the resource.

class Resource {
  public Resource() {
    log.info("creating resource");
  }

  public void doSomething1() {
    log.info("doing something 1");
  }

  public void doSomething2() {
    log.info("doing something 2");
  }

  public void close() {
    log.info("release external resource");
  }
}

We need to remember to call the close method to avoid memory leaks.

Resource resource = new Resource();
resource.doSomething1();
resource.doSomething2();
resource.close(); // need to call this

What if there is an exception?

We can wrap it in a try, finally block

try {
  Resource resource = new Resource();
  resource.doSomething1();
  resource.doSomething2();
} finally {
  resource.close();
}

Or use Automatic Resource Management, but may still forget to wrap in try block

class Resource implements AutoCloseable {
}
try (Resource resource = new Resource()) {
}

We can use execute around method pattern

class Resource {
  // make constructor private
  private Resource() {
    log.info("creating resource");
  }

  public void doSomething1() {
    log.info("doing something 1");
  }

  public void doSomething2() {
    log.info("doing something 2");
  }

  public void close() {
    log.info("release external resource");
  }

  public static void use(Consumer<Resource> operation) {
    Resource resource = new Resource(); // before
    try {
      operation.accept(resource);
    } finally {
      resource.close(); // after
    }
  }
}

class Application {
  public static void main(String[] args) {
    // client code
    Resource.use(resource -> {
      resource.doSomething1();
      resource.doSomething2();
    });
  }
}

Real world application
Typically used in a transaction block,

Transaction.runInTransaction(tx -> {
  ...
});