2022년 3월 23일 TIL

yshjft·2022년 3월 23일
0

데브코스 TIL

목록 보기
3/45

Interface 이야기

1. Interface의 기능

  1. 구현을 강제
    인터페이스는 모든 메서드가 추상 메서드이기에 사용시 구현을 강제한다.

  2. 다형성을 제공
    호스트 코드(설정 파일들 드에 따라 결정을 하는 부분)에 따라서 메서드 동작이 달라진다.

  3. 결합도를 낮추는 효과(의존성을 역전 )

  • 추상체와의 결합 → 결합도가 낮아진다.
  • 의존성을 외부로부터 전달 받았다.
// Login 사용
class UserService implements Login {
	private Login login
    ...
}

interface Login {...}

// Login 구현
class NaverLogin implements Login {...}
class KakaoLogin implements Login {...}

→ 의존성을 주입받았다(DI, Dependency Injection)
→ 의존도를 낮춘다.
→ Dependency Inversion(의존성 역전)이 되었다.

2. default Method 기능

  • Java 8 이상 부터 가능한 개선 사항
  • default 메서드를 통하여 인터페이스가 구현체를 가질 수 있게 되었다!
  • 오버라이드 할 수 있다.
  • Adapter 역할을 할 수 있다.
    • Adapter는 언제 사용하는가?
      인터페이스의 추상메서드는 반드시 모두 구현해야한다. 이는 필요 없는 메서드까지 구현해야 하는 문제를 발생시킨다.
    • Adapter Class 이용
      class AClass extends Adapter {
      	@Override
        public void method1() {...} // 필요한 것만 오버라이드 한다.  	
      }
      
      class Adapter implements interface {
      	@Override
        public void method1() {...}
        
        @Override
        public void method2() {...}
      }
      
      interface AInterface {
      	void method1(); // AClass에게 필요 O
        void method2(); // AClass에게 필요 X
      }
      Adapter class를 이용하여 필요한 메서드만 구현할 수 있게 되었다. 하지만 Java는 단일 상속만 가능하다. 만약 AClass가 이미 상속을 받고 있다면 Adapter class를 사용할 수 없다.
    • After
      class AClass extends Object implements AInterface {
      	@Override
        public void method1() {...} // 필요한 것만 오버라이드 한다.  	
      }
      
      interface AInterface {
      	default void method1(){}; // AClass에게 필요 O
        default void method2(){}; // AClass에게 필요 X
      }
      Java의 다중 상속 불가능으로 인해 생긴 위의 문제를 default 메서드를 통하여 해결할 수 있다.

3. Functional Interface(함수형 인터페이스)

  • 추상메소드가 하나만 존재하는 인터페이스
  • default 나 static 메소드가 같이 있어도 된다. 추상 메서드만 하나면 된다!
  • @FunctionalInterface 을 달아준다.
  • FunctionalInterface에 있는 추상메소드를 함수라고 부른다.
@FunctionalInterface
interface MyMap {
  void map();

  default void sayHello(){...}
  default void sayBye(){...}
}
  • java.util.function
    • FunctionalInterface
    • 재사용하고 범용적으로 활용될 수 있는 인터페이스들이 모아져 있다.
    • Predicate
      public interface Predicate<T> {
      	// return true if the input argument matches the predicate, otherwise false
      	boolean test(T t);
      }
    • Consumer
      public interface Consumer<T> {
      	// Performs this operation on the given argument.
      	void accept(T t);
      }
    • Function
      public interface Function<T, R> {
      	// Applies this function to the given argument.
      	R apply(T t);
      }

3.1. 인터페이스 임시 생성기

  • 인터페이스는 스스로 new 할 수 없다.

  • 인터페이스를 사용하기 위해서는 다른 클래스가 필요하다. → 귀찮음 발생😮‍💨

  • 익명클래스를 사용해서 인터페이스의 인스턴스를 생성하고 구현을 바로 정의한다.

interface MySupply {
  String supply();
}

// 익명 클래스 생성
MySuuply s = new MySupply() {
    @Override
    public String supply() {
      return "Hello World";
    }
}.supply();

4. Lamda 표현식

  • 익명 메소드를 사용해서 간결한 인터페이스 인스턴스 생성 방법
  • FunctionalInterface 에서 가능합니다.
    • 구현해야 할 메서드가 1개만 있어야 뻔하니까...
  • 간결하게 표현이 가능한다.
    • 뻔한 부분을 제거한다
    • 한줄일 경우 {}, return 생략
    • Before
    MyRunnable r = new MyRunnable() {
        @Override
        public void run() {
           MySupply s = new MySupply() {
               @Override
               public String supply() { return "Hello Hello"; }
           };
           System.out.println(s.supply());
        }
    };
    • After
    MyRunnable r3 = () -> {
       // 익명 함수
       MySupply s2 = () -> "Hello Hello";
       System.out.println(s2.supply());
    };

4.1. 메소드 레퍼런스

  • 람다 표현식에서 입력되는 값을 변경 없이 바로 사용하는 경우
  • 최종으로 적용될 메소드의 레퍼런스를 지정해 주는 표현 방식
  • 형식: ClassName::MethodName
  • 입력값을 변경하지 말라는 표현방식이기도 하다.
    • 개발자의 개입을 차단함으로써 안정성을 얻을 수 있다.
@FunctionalInterface
public interface MyMapper<IN, OUT> {
    OUT map(IN s);
}

// lamda
MyMapper<String, Integer> m = s1 -> s1.length();

// method reference
MyMapper<String, Integer> m = String::length;

Lamda와 method reference는 IntelliJ의 도움을 받으며 익숙해지자!

profile
꾸준히 나아가자 🐢

0개의 댓글