# SOLID Principles (Series) [PART 2]

> If get to know something new by reading my articles, don't forget to endorse me on [LinkedIn](https://www.linkedin.com/in/rommansabbir/)

### OCP : Open–Closed Principle.

In this article, we'll talk about **Open/Closed Principle (OCP)** as one of the **SOLID** principles of object-oriented programming.

> OCP Principle states that Software Entities should be open for extension, but closed for modification.

As a result, when any requirements change then the entity can be extended, but not modified.

### Example of **OCP**:

Let's consider, we're building a view action component that might have several actions, such as single click and double click.

```plaintext
interface ViewAction {}
```

Let's define two classes `SingleClick` and `DoubleClick` and both of the implement `ViewAction`.

```plaintext
class SingleClick : ViewAction {
    fun onSingleClickAction() {
        println("Single Click Action Executed")
    }
}
```

```plaintext
class DoubleClick : ViewAction {
    fun onDoubleClickAction() {
        println("Double Click Action Executed")
    }
}
```

Let's create another `Object` called `ViewActionExecutor`, which expose an `API` called `perform()` which take `ViewAction` as a parameter. Inside the `perform()` method, method calls the `Implementation of APIs` respectfully based on the `Instance` checking.

```plaintext
object ViewActionExecutor {
    fun perform(viewAction : ViewAction) {
        if (viewAction is SingleClick) {
            viewAction.onSingleClickAction()
        }
        if (viewAction is DoubleClick) {
            viewAction.onDoubleClickAction()
        }
        else { //ignore }
    }
}
```

Till so far, everything is okay and working fine without any issue. **But**, wait a minute...

What if there are some additional requirements for `ViewAction`?. Let's say we have to implement more four classes called `SwipeLeft`, `SwipeRight`, `SwipeTop`, `SwipeBottom` and all of them implement `ViewAction`.

```plaintext
class SwipeLeft : ViewAction {
    fun onSwipeLeftAction() {
        println("SwipeLeft Action Executed")
    }
}
class SwipeRight : ViewAction {
    fun onSwipeRightAction() {
        println("SwipeRight Action Executed")
    }
}
class SwipeTop : ViewAction {
    fun onSwipeTopAction() {
        println("SwipeTop Action Executed")
    }
}
class SwipeBottom : ViewAction {
    fun onSwipeBottomAction() {
        println("SwipeBottom Action Executed")
    }
}
```

So, our final `Executor` class would be

```plaintext
object ViewActionExecutor {
    fun perform(viewAction : ViewAction) {
        if (viewAction is SingleClick) {
            viewAction.onSingleClickAction()
        }
        if (viewAction is DoubleClick) {
            viewAction.onDoubleClickAction()
        }
        if (viewAction is SwipeLeft) {
            viewAction.onSwipeLeftAction()
        }
        if (viewAction is SwipeRight) {
            viewAction.onSwipeRightAction()
        }
        if (viewAction is SwipeTop) {
            viewAction.onSwipeTopAction()
        }
        if (viewAction is SwipeBottom) {
            viewAction.onSwipeBottomAction()
        }
        else { //ignore }
    }
}
```

Now, as we can see, the more `ViewAction` is added to the system, the more `If Else` condition added to the `Executor` by checking `Instance` first.

> This is where the main problem occurs, becuase each implementation of `ViewAction` has different `API` or `Method` or `Function` name (ex, `SwipeLeft` contain `onSwipeLeftAction()` API and `SwipeRight` contain `onSwipeRightAction()`).

As a result, we need to added more `If` condition to the executor class, which is a bad practice and will lead to serious problem in future as code base will grow more and more. It will be so much hard to maintain and refactor or fixing bugs.

We can solve this problem by following **OCP : Open-Closed Principle**

> As we've seen our component is not yet **OCP** compliant. The code in the respective method will change with every incoming new operation support request. So, we need to extract this code and put it in an abstraction layer.

One solution is to delegate each operation into their respective class:

```plaintext
interface ViewAction { 
    fun perform() 
}
```

So, all of the implmentations (`ViewAction`) classes would be:

```plaintext
class SingleClick : ViewAction {
    @override fun perform() {
        println("Single Click Action Executed")
    }
}
class DoubleClick : ViewAction {
    @override fun perform() {
        println("Double Click Action Executed")
    }
}
class SwipeLeft : ViewAction {
    @override fun perform() {
        println("SwipeLeft Action Executed")
    }
}
class SwipeRight : ViewAction {
    @override fun perform() {
        println("SwipeRight Action Executed")
    }
}
class SwipeTop : ViewAction {
    @override fun perform() {
        println("SwipeTop Action Executed")
    }
}
class SwipeBottom : ViewAction {
    @override fun perform() {
        println("SwipeBottom Action Executed")
    }
}
```

And, finally our `Executor` class would be :

```plaintext
object ViewActionExecutor {
    fun perform(viewAction : ViewAction) {
        viewAction.perform()
    }
}
```

`Executor` is now super clean and understandable properly. On the other hand, each of implementation is moved to `perform()` API.

### Recap

* `ViewAction` has its own `API` called `perform()` and childs who implement `ViewAction` must `override` the `perform()` API.
    
* Business logic is different for each child but the identification still remains the same.
    
* There is no more `If Else` in the `Executor` object, no need to check object `Instance` and call different `APIs` to perform respective operations.
    
* `Childs` implement `ViewAction` with respective business logic and `Executor` just perform the `Execution`.
    

> Now, the class/interface/base is closed for modification but open for an extension and we acheived `Open-Closed Principle` successfully.

In the next article we will talk about **Liskov Substitution Principle**.

That's it for today. Happy Coding...
