Published on

[SOLID] Open-Close Principle

Authors
  • avatar
    Name
    Khánh
    Twitter

When we use:

Statement

software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

Explanation

According to this principle, a module should ensure two factors:

  • Open for Extension: a module should be easily extendable and upgradeable when new requirements arise.
  • Closed for Modification: it should limit or prevent modifications to the existing module.

A typical example of this is the extensions in VS Code. For each language or framework, VS Code has specific extensions that support those languages or frameworks. This demonstrates that VS Code can be considered as a non-changing part (closed for modification) and yet extendable (open for extension).

Example

Using the classic example of Shap and Circle, Triangle, Square

class Shape {}

class Circle extends Shape {
	let radius: number;
}

class Triangle extends Shape {
	let firstSide: number;
	let secondSide: number;
	let thirdSide: number;
}

class Square extends Shape {
	let height: number;
}

// Area calculate the area of the Shape
class Area {
	public calcArea(shape: Shape) {
		if(shape === typeof Circle){
			// the area of the Circle
		}
		if(shape === typeof Triangle){
			// the area of the Triangle
		}
		if(shape === typeof Square){
			// the area of the Square
		}
	}
}

Comment: If we need to calculate the area of a Trapezoid, a Parallelogram, etc., we would have to modify the calcArea class to add more if statements.

Apply Open-Close principle, we can modify it as follows:

class Shape {
	public getArea(){}
}

class Circle extends Shape {
	let radius: number;
	public getArea(){
		return this.radius * this.radius * Math.PI;
	}
}

class Triangle extends Shape {
	let firstSide: number;
	let secondSide: number;
	let thirdSide: number;
	public getArea(){
		let totalHalf = (this.firstSide + this.secondSide + this.thirdSide) / 2;
    let area += Math.Sqrt(totalHalf * (totalHalf – this.firstSide) * 
        (totalHalf – this.secondSide) * (totalHalf – this.thirdSide));
    return area;
	}
}

class Square extends Shape {
	let height: number;
	public getArea(){
		return Math.Sqrt(this.Height);
	}
}

// The Area class
class Area {
	public calcArea(shape: Shape) {
		return shape.getArea();
	}
}

Conclusions

Applying this principle to design requires the designer to clearly understand what needs to be changed, which is very difficult for developers. This requires broad vision and the ability to anticipate, understand the system, and the business being developed.