-
Notifications
You must be signed in to change notification settings - Fork 0
SOLID Principle
Mac edited this page Feb 23, 2024
·
24 revisions
- A class should have one and only one reason to change
- Meaning that a class should only have one job.
- Solution : Aim for high cohesion and low coupling
- High cohesion : The degree to which the elements inside a module belong together
- Low coupling : The degree of interdependence between software modules
Benefit :
- Class can be reusable.
- Easy to find where the problem come from
- Classes should be open for extension but closed for modification.
- Closed for modification means that once you have developed a class you should never modify it, except to correct bugs.
public class Warrior {
public void attack(String weapon) {
if("sword".equals(weapon)) {
System.out.println("Slash !");
} else if ("bow".equals(weapon)) {
System.out.println("Shoot !");
} else if ("knife".equals(weapon)) {
System.out.println("Stab !");
}
// More weapon will be add here. This is not good.
}
}
// TO BE
public class Warrior {
public void attack(Weapon weapon) {
weapon.use();
}
}
interface Weapon {
void use();
}
class Sword implements Weapon {
public void use() {
System.out.println("Slash !");
}
}
class Bow implements Weapon {
public void use() {
System.out.println("Shoot !");
}
}
class Knife implements Weapon {
public void use() {
System.out.println("Stab !");
}
}- Ability to replace any instance of parent class with an instance of one of its child classes without negative side effects.
- Any child type of a parent type should be able to stand in for that parent without things blowing up.
- Derived class must be usable through the base class interface, without the need for the user to know the different.
- Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program
- An example of this is with a Bird base class. You might assume that it should have a fly method. But what about the birds that can’t fly? Like a Penguin. In this example, fly should not be in the base class as it does not apply to all subclasses.
public class App {
public static void main(String[] args) {
Rectangle r = new Rectangle();
r.setHeight(10);
r.setWidth(5);
System.out.println(r.area()); // 50
r = new Square();
r.setHeight(10);
r.setWidth(5);
System.out.println(r.area()); // 50, Wrong because Height and width of Square must equal.
}
}
class Rectangle {
private int width;
private int height;
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int area() {
return width * height;
}
}
class Square extends Rectangle {
}
// TO BE
public class App {
public static void main(String[] args) {
Rectangle r = new Rectangle();
r.setHeight(10);
r.setWidth(5);
System.out.println(r.area()); // 50
r = new Square();
r.setHeight(10);
r.setWidth(5);
System.out.println(r.area()); // 25
}
}
class Rectangle {
private int width;
private int height;
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int area() {
return width * height;
}
}
class Square extends Rectangle {
@Override
public void setWidth(int width) {
super.setWidth(width);
super.setHeight(width);
}
@Override
public void setHeight(int height) {
super.setWidth(height);
super.setHeight(height);
}
}- Clients should not be forced to implement interface that they does not use.
- Create multiple, smaller, cohesive interfaces.
- Cohesive, meaning they have groups of operations that logically belong together.
Benefit :
- Client class don't have to override unnecessary method from Interface.
interface Cat {
void walk();
void eat();
}
class PersianCat implements Cat {
public void walk() {
System.out.println("PersianCat is walking");
}
public void eat() {
System.out.println("PersianCat is eating");
}
}
class RobotCat implements Cat {
public void walk() {
System.out.println("RobotCat is walking");
}
public void eat() {
// Robot cat don't really need to eat.
}
}
// TO BE
interface Walkable {
void walk();
}
interface Eatable {
void eat();
}
class PersianCat implements Walkable, Eatable {
public void walk() {
System.out.println("PersianCat is walking");
}
public void eat() {
System.out.println("PersianCat is eating");
}
}
class RobotCat implements Walkable {
public void walk() {
System.out.println("RobotCat is walking");
}
}- High level modules should not depend on low level modules, both should depend on abstractions.
- High level module is a module which depends on other modules. For example, UserRestController that depends on UserService.
- Abstractions should not depend on details. Details should depend upon abstractions.
- Use dependency injection to reduce coupling between class.
- While dependency injection is a design pattern that allows us to separate creation from use.
Benefit :
- Easy to write unit test. We can mock low level modules
- Easy to change when high level module want to change low level module.
class StorageService {
public void store(Object o) {
// StorageService depend on FileStorage.
FileStorage fs = new FileStorage();
fs.save(o);
}
}
class FileStorage {
public void save(Object o) {
}
}
// TO BE
class StorageService {
private Storage storage;
public void setStorage(Storage storage) {
this.storage = storage;
}
public void store(Object o) {
storage.save(o);
}
}
interface Storage {
void save(Object o);
}
class FileStorage implements Storage {
public void save(Object o) {
}
}- Single-responsibility Principle : A class should have only one job
- Open-Closed Principle : A class should open for extension and close for mofication
- Liskov Substitution Principle : Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program
- Interface segregation principle : Create small interface with minimal number of method.
- Dependency inversion : High level modules should not depend on low level modules, both should depend on abstractions to reduce coupling between module
Reference
- https://zeroturnaround.com/rebellabs/object-oriented-design-principles-and-the-5-ways-of-creating-solid-applications/
- https://scotch.io/bar-talk/s-o-l-i-d-the-first-five-principles-of-object-oriented-design
- https://dzone.com/articles/the-solid-principles-in-real-life
- http://deviq.com/solid/
- https://medium.com/@andy.sek94/s-o-l-i-d-principles-for-software-development-611b5f7170de