Written by Luka Kerr on November 13, 2018

Inheritance

public abstract class Parent {
  // Can't create instance of Parent
}

public class Child extends Parent {
  // Can create instance of Child
  // Child inherits any methods and properties in Parent
}

public interface xyz {
  void abc() throws IOException;
}

public interface pqr {
  void abc() throws FileNotFoundException;
}

public class Main implements xyz, pqr {
  // The last interface takes a higher precedence
  public void abc() throws FileNotFoundException;
}

Polymorphism

public interface Vegetarian {}
public class Animal {}

// Polymorphic since a Deer IS-A Animal, IS-A Vegetarian, IS-A Deer, IS-A Object
public class Deer extends Animal implements Vegetarian {}

Access Modifiers

Modifier Same Class Same Package Subclass Everyone
public X X X X
protected X X X  
default X X    
private X      

Law Of Demeter

public class O {

  private E myE = new E();

  public void method M(E paramE) {
    // Rule 1
    this.W();

    // Rule 2
    paramE.N();

    // Rule 3
    E localE = new E();
    localE.N();

    // Rule 4
    this.myE.N();
  }

  private void method W() {}
}

public class E {
  public void method N() {}
}

Liskov Substitution Principle

Patterns

Strategy Pattern

State Pattern

Iterator Pattern

Template Method Pattern

Composite Pattern

Decorator Pattern

public interface Component {
  void doOperationA();
  void doOperationB();
}

public class ConcreteComponent implements Component {
  @Override
  void doOperationA();

  @Override
  void doOperationB();
}

public abstract class Decorator implements Component {
  private ConcreteComponent cc;
}

public class ConcreteDecoratorX extends Decorator {}

Observer Pattern

public interface Observer {
  void update();
}

public class Observable {
  private ArrayList<Observer> observers;
  void addObserver(Observer o);
  void removeObserver(Observer o);
  void notifyObservers():
}

public class Display implements Observer {
  @Override
  void update();
}

Factory Method Pattern

public interface Product {}

public abstract class Creator {
  abstract public Product makeProduct();
}

public class ConcreteCreator extends Creator {
  @Override
  public Product makeProduct();
}

Builder Pattern

public class User {
  private final String name;
  private final String phone;
  // ...

  private User(UserBuilder ub) {
    this.name = ub.name;
    this.phone = ub.phone;
    // ...
  }

  public static class UserBuilder {
    private final String name;
    private final String phone;
    // ...

    public UserBuilder(String name) {
      this.name = name;
    }

    public UserBuilder phone(String phone) {
      this.phone = phone;
      return this;
    }

    public User build() {
      return new User(this);
    }
}

// In use
User user = new User.UserBuilder("Bob")
  .phone("1234")
  .build();

Singleton Pattern

public final class Singleton {
  private static final Singleton instance = new Singleton();

  private Singleton() {}

  public static Singleton getInstance() {
    return instance;
  }
}

Command Pattern

public interface Command {
  void execute();
}

// Invoker
public class Switch {
  private ArrayList<Command> history;

  public void storeAndExecute(Command cmd);
}

// Receiver
public class Light {
  public void turnOn();
  public void turnOff();
}

// Command object
public class FlipUpCommand implements Command {
  @Override
  public void execute();
}

Visitor Pattern

Principles

Open Closed Principle

Single Responsibility Principle

Dependency Injection Principle

Design By Contract

/**
 * @invariant balance >= 0
 */
public class Account {

  /**
   * Deposit into an account
   * @pre amount > 0
   * @post balance = balance + amount
   */
  public void deposit(float amount);
}

Test Driven Development

  1. Write a test that fails
  2. Implement the code to pass the test
  3. Refactor and eliminate redundancy, goto 1

Generics

public class Bag<T> {
  private T t;
  public T get();
  public void set(T t);
}

Threads

public class Counter implements Runnable {
  private int count = 0;

  @Override
  public void run() {
    for (int i = 0; i < 5; i++)
      System.out.println(Thread.currentThread().getName() + " : " + counter++);
  }
}

// Usage
Runnable c = new Counter();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();

Concurrency

public class Counter implements Runnable {
  private int count = 0;

  // Using synchronized to lock critical sections
  public void add(int value) {
    synchronized(this) {
      count += value;
    }
  }

  @Override
  public void run() {}
}

Code Smells

Refactoring Techniques