Solid Principles

The following five concepts make up our SOLID principles:

  1. Single Responsibility

  2. Open/Closed

  3. Liskov Substitution

  4. Interface Segregation

  5. Dependency Inversion

Single Responsibility

Testing | Organization | Less Coupling PageObjects should have only locators. Models should have only properties.

Open/Closed Principle

Objects or entities should be open for extension but closed for modification.

Use if conditions to extend functionality rather than modification of existing function.

public class Guitar {

    private String make;
    private String model;
    private int volume;

    //Constructors, getters & setters
}
//If we need to add new functionality extend guitar instead of modifiying
public class SuperCoolGuitarWithFlames extends Guitar {

    private String flameColor;

    //constructor, getters + setters
}

Liskov Substitution

if class A is a subtype of class B, we should be able to replace B with A without disrupting the behavior of our program.

public class Bird {
   public void fly() {
      System.out.println("I'm flying");
   }
   public void walk() {
    System.out.println("I'm walking");
   }
}

//No problem as bird can both fly & walk
public class Dove extends Bird{

}
//problem as penquin can only walk. 
// we need to modify bird now
public class Penguin extends Bird{

}

Interface Segregation

public interface BearKeeper {
    void washTheBear();
    void feedTheBear();
    void petTheBear();
}
//split above interface
public interface BearCleaner {
    void washTheBear();
}

public interface BearFeeder {
    void feedTheBear();
}

public interface BearPetter {
    void petTheBear();
}

//Implementation
public class BearCarer implements BearCleaner, BearFeeder {

    public void washTheBear() {
        //I think we missed a spot...
    }

    public void feedTheBear() {
        //Tuna Tuesdays...
    }
}

public class CrazyPerson implements BearPetter {

    public void petTheBear() {
        //Good luck with that!
    }
}

Dependendcy Inversion

The principle of dependency inversion refers to the decoupling of software modules. This way, instead of high-level modules depending on low-level modules, both will depend on abstractions.

public class Windows98Machine {

    private final StandardKeyboard keyboard;
    private final Monitor monitor;

    public Windows98Machine() {
        monitor = new Monitor();
        keyboard = new StandardKeyboard();
    }

}
//Windows98Machine tightly coupled to standardkeyboard in above class

public interface Keyboard { }

public class Windows98Machine{

    private final Keyboard keyboard;
    private final Monitor monitor;

    public Windows98Machine(Keyboard keyboard, Monitor monitor) {
        this.keyboard = keyboard;
        this.monitor = monitor;
    }
}

public class StandardKeyboard implements Keyboard { }