---
# System prepended metadata

title: Introduction of Interface in Spring Boot and Java8
tags: [Interface, Java, Reading notes, Spring Boot]

---

---
title: Introduction of Interface in Spring Boot and Java8
description: 
---  

# Introduction of Interface in Spring Boot and Java8
###### Author: TYT
###### Tags: `Reading notes`, `Java`, `Spring Boot`,`Interface`

- [Introduction](#Introduction)
    - What, why, when, and how
- [Usage](#Usage)
    - Single and muliple implement (inter-, intra, and unit test)
- [Misuse and overuse](#Misuse-and-overuse)
- [Summary](#Summary)
- [Quiz](#Quiz)  

---

## Introduction
### What is interface?
- Interface is a reference type.
- Contain method signature, default method, and static method.
- Cannot be instantiated, only be implemented by class and extended by interface.

```java
public interface RoadVehicle {

    String drive(String direction);

    // can be used when class implemented.
    default void turnoff() {
        System.out.println("turn off");
    }

    // can be used without implementaton.
    static void honk() {
        System.out.println("Do Do!");
    }
}
```   

### Why use interface?
- Achieve
    - Loose coupling
       :::spoiler Tight coupling vs. Loose coupling
       - Tight coupling
        ```java
        public class Person {

            public static void main(String[] args){

                Shopping shopping = new Shopping();
                shopping.pay();
            }
        }
        ```
        We have to commit and uncommit for switching payment instrument to pay. 
        Otherwise, creat more shopping class, Shopping1 and Shopping2, etc. to cater to payment instrument instead of commit and uncommit.
        ```java
        public class Shopping {

            public void pay(){
                CreditCard creditCard = new CreditCard();
                creditCard.pay();
        //        SmartPhone smartPhone = new SmartPhone();
        //        smartPhone.pay();
            }
        }
        ```
        ```java
        public class CreditCard {

            public void pay(){
                System.out.println("Pay by credit card.");
            }
        }
        ```
        ```java
        public class SmartPhone {

            public void pay(){
                System.out.println("Pay by smart phone.");
            }
        }
        ```
        - Loose coupling
        Person can controll the payment instrument he/she want, kind of IoC I think.
        ```java
        public class Person {

            public static void main(String[] args){
                PaymentInstrument creditCard = new CreditCard();
        //        PaymentInstrument smartPhone = new SmartPhone();

                Shopping shopping = new Shopping(creditCard);
                shopping.pay();
            }
        }
        ```
        Creat variable to switch payment instrument easier.
        ```java
        public class Shopping {

            private PaymentInstrument paymentInstrument;

            public Shopping(PaymentInstrument paymentInstrument){
                this.paymentInstrument = paymentInstrument;
            }

            public void pay() {
                paymentInstrument.pay();
            }

        }
        ```
        ```java
        public interface PaymentInstrument {

            void pay();
        }
        ```
        ```java
        public class CreditCard implements PaymentInstrument{

            @Override
            public void pay(){
                System.out.println("Pay by credit card.");
            }
        }
        ```     
        ```java
        public class SmartPhone implements PaymentInstrument{

            @Override
            public void pay(){
                System.out.println("Pay by smart phone.");
            }
        }
        ```        
        :::
        ::: spoiler Recommended vedio
        {%youtube ifufbHjIQCo %} 
        :::
    - Multiple implement and interitance
    - Switch implement easily


### When use interface

- Specify the "behavior" of a particular data type
- Expect the unrelated class whould implenment the interface
    - Storage device (interface) - Optical disc (1965), Floppy disk drive (1971), and USB flash drive (2000), etc.(class)
- Multiple implement and interface 
    - Class USB flash drive implenments interface storage device and charging equipment.
    
### How to use interface?

- Interface
    :::spoiler Use "extends" to extend the interface.
    ``` java
    public interface I002 extends I001 {
        //TODO
    }
    ```
    :::
    :::spoiler  Use "," when mutiple interface is extended. 
    ``` java
    public interface I003 extends I001, I002 {
        //TODO
    }
    ```
    :::
- Class 
    :::spoiler Use "implenments" to implenments the interface
    ``` java
    public class C001 implenments I001 {
        //TODO
    }
    ```
    :::
    :::spoiler Use "," when mutiple interface is implenmented. 
    ``` java
    public interface C002 implenments I001, I002 {
        //TODO
    }
    ``` 
    :::
    :::spoiler Should create all method body which method signature is declared in interface. 
    ``` java
    public interface I001 {
        String greeting ();
    }
    ```
    ```java
     public class C001 implenments I001 {

         publc greeting (){
             return "hello";
         }
     }
    ```
    :::
## Usage
### One implement

:::spoiler Instantiate implement in native Java, likes ```List<int> list = new ArrayList<>()```, ```Map<String, Object> map = new HasMap<>()```, etc.

```java
@RestController
@RequestMapping("/One")
public class PersonA1Controller {

    @RequestMapping(value = "/PersonA1", method = RequestMethod.GET)
    public String PersonA1(){

        PaymentInstrumentA paymentInstrumentA = new CreditCardA();
        return paymentInstrumentA.pay(); // Pay by credit card A.
    }
}
```
``` java
public interface PaymentInstrumentA {

    String pay ();
}
```
```java
@Service
public class CreditCardA implements PaymentInstrumentA {

    @Override
    public String pay(){
        return "Pay by credit card A.";
    }
}
```
:::
:::spoiler Use @Service/ @Component in Spring Boot
```java
@RestController
@RequestMapping("/One")
public class PersonA2Controller {

    @Autowired
    PaymentInstrumentA paymentInstrumentA;

    @RequestMapping(value = "/PersonA2", method = RequestMethod.GET)
    public String PersonA2(){
       return paymentInstrumentA.pay();
    }
}
```
``` java
public interface PaymentInstrumentA {

    String pay ();
}
```
```java
@Service
public class CreditCardA implements PaymentInstrumentA {

    @Override
    public String pay(){
        return "Pay by credit card A.";
    }
}
```
:::  
### Multiple implement

- Inter-class
    :::spoiler Use default name (lowercase in the first letter) as variable name.
    ```java
    @RestController
    @RequestMapping("/Multiple/Inter")
    public class PersonB1Controller {

        @Autowired
        PaymentInstrumentB creditCardB1ServiceImpl;

        @RequestMapping(value = "/PersonB1", method = RequestMethod.GET)
        public String PersonB1(){
            return creditCardB1ServiceImpl.pay(); // Pay by credit card B1.
        }
    }
    ```
    ```java
    public interface PaymentInstrumentB {
        String pay();
    }
    ```
    ``` java
    @Service
    public class CreditCardB1ServiceImpl implements PaymentInstrumentB {

        @Override
        public String pay() {
            return "Pay by credit card B1.";
        }
    }
    ```
    :::
    :::spoiler Name implenment and use @Qualifier to specify default implenment 
   
    ```java
    @RestController
    @RequestMapping("/Multiple/Inter")
    public class PersonB2Controller {

        @Qualifier("CreditCardB2ServiceImpl")
        @Autowired
        PaymentInstrumentB paymentInstrumentB;

        @RequestMapping(value = "/PersonB2", method = RequestMethod.GET)
        public String pay(){
            return paymentInstrumentB.pay(); // Pay by credit card B2.
        }
    }
    ```
    ```java
    public interface PaymentInstrumentB {
        String pay();
    }
    ```    
    ``` java
    @Service("CreditCardB2ServiceImpl")
    public class CreditCardB2ServiceImpl implements PaymentInstrumentB {

        @Override
        public String pay() {
            return "Pay by credit card B2.";
        }
    }
    ```
    :::
    :::spoiler Use @Primary to specify default implenment 
    ```java
    @RestController
    @RequestMapping("/Multiple/Inter")
    public class PersonB3Controller {

        @Autowired
        PaymentInstrumentB creditCardCService;

        @RequestMapping(value = "/PersonB3", method = RequestMethod.GET)
        public String pay(){
            return creditCardCService.pay(); // Pay by credit card B3.
        }
    }
    ```
    ```java
    public interface PaymentInstrumentB {
        String pay();
    }
    ```       
    ``` java
    @Primary
    @Service
    public class CreditCardB3ServiceImpl implements PaymentInstrumentB {

        @Override
        public String pay() {
            return "Pay by credit card B3.";
        }
    }
    ```
    :::
- Intra-class
    :::spoiler Instantiate implenment to switch
    ```java
    @RestController
    @RequestMapping("/Multiple/Intra")
    public class PersonCController {

        @Qualifier("CreditCardC1")
        @Autowired
        PaymentInstrumentC paymentInstrumentC;

        @RequestMapping(value = "/PersonC1", method = RequestMethod.GET)
        public String payD001(){
            return paymentInstrumentC.pay(); // Pay by credit card C1.
        }

        @RequestMapping(value = "/PersonC2", method = RequestMethod.GET)
        public String payD002(){
            PaymentInstrumentC paymentInstrumentC = new CreditCardC2();
            return paymentInstrumentC.pay(); // Pay by credit card C2.
        }
    }

    ```
    ``` java
    public interface PaymentInstrumentC {

        String pay();
    }
    ```
    ```java
    //@Primary
    @Service("CreditCardC1")
    public class CreditCardC1 implements PaymentInstrumentC {

        @Override
        public String pay() {
            return "Pay by credit card C1.";
        }
    }
    ```
    ```java
    @Service("CreditCardC2")
    public class CreditCardC2 implements PaymentInstrumentC {

        @Override
        public String pay() {
            return "Pay by credit card C2.";
        }
    }
    ```
    :::
- Will Run build failed if don't use @Primary, @Qualifer, and default name, e.g. [stackoverflow](https://stackoverflow.com/questions/46343560/class-required-a-single-bean-but-2-were-found).
    ```
    Description:
    Field {interfaceName} in {class which declars interface}required a single bean, but 2 were found: 
        {implenment01}: defined in fill {file path}
        {implenment02}: defined in fill {file path}
    Action:
    Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
    ```
- With unit test
    - App code
        - Use @Primary/ name implenment, and use @Qualifier/ default name to specify implenment.
        ```java 
        @RestController
        @RequestMapping("Multiple/UnitTest")
        public class PersonDController {

            @Autowired
            PaymentInstrumentD paymentInstrumentD;

            @RequestMapping(value = "/PersonD", method = RequestMethod.GET)
            public String pay(){
                return paymentInstrumentD.pay(); // Pay by credit card D.
            }
        }
        ```
        ```java 
        public interface PaymentInstrumentD {

            String pay();
        }
        ```
        ```java 
        // @Primary
        @Service
        public class CreditCardD implements PaymentInstrumentD {

            @Override
            public String pay() {
                return "Pay by credit card D.";
            }
        }
        ```
    - Unit test code
       :::spoiler use default name/ @Qualifier to specify implenment.
        - default name
        ```java
        @RunWith(SpringRunner.class)
        @ContextConfiguration(classes=ShareApplication.class)
        public class PersonDControllerTest1 {

            @Autowired
            PaymentInstrumentD creditCardDTest1;

            @Test
            public void pay(){
                System.out.println(creditCardDTest1.pay());
            }
        }
        ```
        ```java
        @Service
        public class CreditCardDTest1 implements PaymentInstrumentD {

            @Override
            public String pay() {
                return "Pay by credit card D Test 1.";
            }
        }
        ```
        - @Qualifier
        ```java
        @RunWith(SpringRunner.class)
        @ContextConfiguration(classes=ShareApplication.class)
        public class PersonDControllerTest2 {


            @Qualifier("CreditCardDTest2")
            @Autowired
            PaymentInstrumentD paymentInstrumentD;

            @Test
            public void pay(){
                System.out.println(paymentInstrumentD.pay());
            }
        }
        ```
        ```java
        @Service("CreditCardDTest2")
        public class CreditCardDTest2 implements PaymentInstrumentD {

            @Override
            public String pay() {
                return "Pay by credit card D Test 2.";
            }
        }
        ```
        :::
        :::spoiler Will get return from app code if do not use default name/ @Qualifier to specify implenment.
        ```java
        @RunWith(SpringRunner.class)
        @ContextConfiguration(classes=ShareApplication.class)
        public class PersonDControllerTest2 {


            @Qualifier("CreditCardDTest2")
            @Autowired
            PaymentInstrumentD paymentInstrumentD;

            @Test
            public void pay(){
                System.out.println(paymentInstrumentD.pay());
            }
        }
        ```
        ```java
        @Service("CreditCardDTest2")
        public class CreditCardDTest2 implements PaymentInstrumentD {

            @Override
            public String pay() {
                return "Pay by credit card D Test 2.";
            }
        }
        ```
        :::
    - App code still get return from app code's implenment, even unit test use @Primary.

    - Will Run build failed if don't use @Primary, @Qualifer, and default name.
        ```
        Description:
        Field {interfaceName} in {class which declars interface}required a single bean, but 2 were found: 
            {implenment01}: defined in fill {file path}
            {implenment02}: defined in fill {file path}
        Action:
        Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
        ```    
    - If app code and unit test code both use @primary 
        - Run build will be succussed.
        - Run test will be failed.

## Misuse and overuse
- Create interface just in case.
- Create interface is only for a class.
- Create all method body which declare in interface.
- Name implenment after interface.
    - bad
        ``` java
        public interface PaymentInstrument {
            
            String pay();
        }
        ```
        ```java
        @Service
        public class PaymentInstrumentImpl implenments PaymentInstrument {

            publc pay(){
                return "Pay by paymentInstrumentImpl!";
             }
         }
        ```
    - better
        ``` java
        public interface PaymentInstrument {
            String pay();
        }
        ```
        ```java
        @Service
        public class CreditCardVisa implenments PaymentInstrument {

            publc pay(){
                return "Pay by Visa!";
             }
         }
        ```

## Summary
- Interface characteristics
    - Loose coupling.
    - Multiple implenment and ingeritance.
    - Switch implenment easily.
- Usage
    - Create a interface to extend interface.
    - Create a class to implenment interface.
    - Use @Primary or name implenment, e.g. @Service("serviceName") and @Component("componentName")
    - Use default name or @Qualifier to specify implenment when declare interface.
- Misuse and overuse
    - Avoid using without planing.
    - Create interface is only for a class.

## Quiz
- Output of following Code
(A) Hello!
(B) Hi!
    ```java
    public class Main {

        @Autowired
        IService i002ServiceImpl;

        publc static void main(String[] args){
            iService.greeting();
         }
     }
    ```
    ``` java
    public interface IService {

         String greeting ();
    }
    ```
    ```java
    @Primary
    @service("I001")
    public class I001ServiceImpl extends Base {

        publc void greeting(){
            System.out.println("Hello!");
         }
     }
    ```
    ```java
    @Service("I002")
    public class I002ServiceImpl extends Base {

        publc void greeting(){
            System.out.println("Hi!");
         }
     }
    ```

    :::spoiler Answer
        (B) Hello!
    :::


