# Interfacing in Java/Kotlin

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

# Interface - What, Why & How?

* **What:** An interface in ***Java/Kotlin*** is a blueprint of a class. It has static constants and abstract methods. The interface in ***Java/Kotlin*** is a mechanism to achieve **abstraction**.
    
* **Why:**
    
    * To achieve **abstraction**.
        
    * To support the functionality of **multiple inheritance**.
        
    * To achieve **loose coupling**.
        
    * Easier to **test**.
        
    * Increase **flexibility**.
        
    * **Dependency Injection**.
        
* **How:** An interface is declared by using the ***interface*** keyword. It provides total abstraction; means all the methods in an interface are declared with the empty body, and all the fields are public, static and final by default. A **class** that implements an **interface** must implement all the methods declared in the interface.
    

# Practical Example

Let's think about a scenario, we have a Book Store System, where we can save a ***new book record*** and search for books by following by ***Author Name*** only.

```plaintext
data class Book(val id : Int, val name : String, val author : String, val serialNumber : String)
```

```plaintext
interface BookStore{
    fun addNewBook(book: Book): Boolean
    fun searchBook(authorName : String): MutableList<Book>
}
```

We have a model call ***Book*** which has some attributes (***Id, Name, Author, Serial Number***).

We have our *Interface* called **BookStore**, which expose some public APIs (or Simply, Objects Behaviour) to the client.

Here comes the benefits of ***Interfacing***. Client can access only the interface, but not the actual implementation of the system. Which provide security benefits and according to good coding approach, client shouldn't know about the underlying implementation of a system.

Now, let's take a look at the implementation of BookStore.

```plaintext
class DefaultBookStore() : BookStore {
    companion object {
        private val store: MutableList<Book> = mutableListOf()
    }

    override fun addNewBook(book: Book): Boolean {
        if (!store.contains(book)) {
            store.add(book)
            return true
        }
        return false
    }

    override fun searchBook(authorName: String): MutableList<Book> {
        val filteredBooks = mutableListOf<Book>()
        store.forEach {
            if (it.author.contains(authorName, true)) {
                filteredBooks.add(it)
            }
        }
        return filteredBooks
    }

}
```

* `DefaultBookStore` is the impl of `BookStore`.
    
* `DefaultBookStore` contain a static list (`MutableList`), where all books are stored.
    
* `addNewBook(book: Book): Boolean` is designed to store a new book to the list if it's not stored already in the system and return `Boolean` to verify if book is added or not.
    
* `searchBook(authorName: String): MutableList<Book>` should return a list of `Book`, where filtered books are searched based on query (**Author Name**).
    

But we can can't expose the Implementation of the System, instead we will provide the interface `BookStore` to the client.

Now, lets create a `Factory` class who is responsible to provide an instance of `BookSystem`.

```plaintext
object BookStoreFactory {
    private val defaultBookStore: BookStore = DefaultBookStore()

    fun getDefaultBookStore(): BookStore {
        return defaultBookStore
    }
}
```

* `BookStoreFactory` expose a public API to get the instance of `BookStore`.
    
* `getDefaultBookStore(): BookStore` return an instance of `BookStore`, in our case its `DefaultBookStore` where all business logic is defined.
    

# Unit Tests

```plaintext
class BookStoreSystemTest {
    private var bookStore: BookStore? = null

    @Before
    fun setup() {
        bookStore = BookStoreFactory.getDefaultBookStore()
    }

    @Test
    fun `get default book store from factory`() {
        assert(bookStore != null)
    }

    @Test
    fun `add some books to the system`() {
        assert(bookStore?.addNewBook(Book(1, "Test Book 1", "Romman Sabbir", "12")) == true)
        assert(bookStore?.addNewBook(Book(2, "Test Book 2", "Test Author", "1243")) == true)
        assert(bookStore?.addNewBook(Book(3, "Test Book 3", "Forhad An Naim", "12434")) == true)
        assert(bookStore?.addNewBook(Book(4, "Test Book 4", "Romman Sabbir", "12434re")) == true)
    }

    @Test
    fun `search books by author`() {
        val searchedBooks = bookStore?.searchBook("romman") ?: mutableListOf()
        assert(searchedBooks.isNotEmpty())
    }

    @After
    fun tearDown() {
        bookStore = null
    }
}
```

Result:

```plaintext
✅ Tests passed: 3 of 3 tests - 20 ms
```

# Recap

* Interfacing helps to provide abstraction to the system.
    
* Interface expose only behaviour not business logic.
    
* Interface helps to implement multiple inheritance.
    
* Easy to test an object behaviour.
    
* Increase code readability and helps to maintain proper codebase.
    

Happy Coding...
