Interface,Abstract

최형준·2022년 6월 23일
0

Interface 역할

  • 인터페이스는 객체를 어떻게 구성해야 하는지 정리한 설계도입니다.
  • 인터페이스는 객체의 교환성(또는 다형성)을 높여줍니다.
  • 인터페이스 변수에 인터페이스가 구현된 서로 다른 구현 객체를 할당해서 사용이 가능합니다.
  • 구현 객체를 직접 몰라도 인터페이스 메서드만 알아도 객체 호출이 가능하게 합니다.
  • 객체가 인터페이스를 사용하면, 인터페이스 메서드를 반드시 구현해야 하는 제약을 합니다.

추상 메소드와 상수만 멤버로 가질 수 있음

DeFault 메소드

제약 사항

  • 모든 멤버 변수는 public static, final 생략 가능
  • 모든 메소드는 public abstract 생략가능

Interface Static 사용 이유

  • static method는 재정의 불가
  • final은 static block에서 초기화 할수 없고 선언 동시에 초기화

Default 메소드 사용 이유

  • 인터페이스를 상속 받는다면 그에 해당하는 메소드들을 강제 구현해야함, 하지만 상속을 받아 전부 사용 하는것은 아니기 때문에 default를 이용하여 하위호환을 쉽게 이뤄냄 .
  • 예시

public interface Vehicle {
    
    String getBrand();
    
    String speedUp();
    
    String slowDown();
    
    default String turnAlarmOn() {
        return "Turning the vehicle alarm on.";
    }
    
    default String turnAlarmOff() {
        return "Turning the vehicle alarm off.";
    }
}

public class Car implements Vehicle {

    private String brand;
    
    // constructors/getters
    
    @Override
    public String getBrand() {
        return brand;
    }
    
    @Override
    public String speedUp() {
        return "The car is speeding up.";
    }
    
    @Override
    public String slowDown() {
        return "The car is slowing down.";
    }
}

※ 주의할 점

  • 인터페이스는 다중 상속이 가능하기 때문에 Default 를 사용할 경우 동일한 이름의 Default 메소드를 사용하다 보면 다이아몬드 프러블럼이 발생!!!

Diamond Problem 란?

  • 동일한 이름의 메소드를 다중 상속 받아 오버라이딩 하게 되면 누구로부터 해당 메소드를 전달 받았는지 알 수 없기 때문에 컴파일 에러 발생

  • Person

public class Person {
   String nation = "대한민국";

   protected void 가문(){
      System.out.println("진인사대천명");
   }
}
  • Father
public class Father extends Person {
   @Override
   protected void 가문() {
      System.out.println("가나다라마바사");
   }
}
  • Mother
public class Mother extends Person {
   @Override
   protected void 가문() {
      System.out.println("Hello World.");
   }
}
  • Child
public class Child extends Mother ,Father{
   public static void main(String[] args) {
      Child child = new Child();
      System.out.println("내 국적은 "+child.nation+"입니다.");
      child.가문();
   }
}
  • 여기서 Child를 하게 되면 오류가 발생한다, 엄마한테서 왔는지 아빠한테서 왔는지 모르기 때문

방지 방법

  • 인터페이스를 통한 상속

예시

//Person
public interface Person {
   String nation = "대한민국";
   void 가문();
}

//Father
public interface Father extends {
   @Override
   void 가문();
}
//Mother
public interface Mother extends Person {
   @Override
   void 가문();
}
//child
public class Child implements Father, Mother {
   @Override
   void 가문(){
      System.out.println("Hello World.");
   }
  
   public static void main(){
      Child child = new Child();
     
      System.out.println("내 국적은 "+child.nation+"입니다.");
      child.가문();
   }
}
  • 사용 가능한 이유
    • 인터페이스는 구현체가 없는 추상메소드이다. 그렇기 때문에 Mother로 부터 받았는지, Father로 부터 받았는지 알필요 없이 child에서 구현하기 때문에 에러 발생 x

Abstract

추상클래스란?

  • 공통의 메소드들을 추출해서 만든것
  • 추상클래스는 자식클래스에서 받아서 구현해야하기 때문에 private로 선언할 수 없다.

추상 클래스 VS Interface

공통점

  • extends, implements 하는 Class가 Abstract method를 구현하도록 강제하는 공통점을 가짐

차이점

  • 자바의 특성상 한개의 클래스만 상속이 가능하여 해당 클래스의 구분을 추상클래스 상속을 통해 해결하고, 할 수 있는 기능들을 인터페이스로 구현합니다.
  • 사용 용도에 따라 구분된다.
  • 추상클래스는 공통의 확실한 부분을 구현하기위해
  • 인터페이스는 선택적 구현을 위해 사용
public abstract class Teacher {
    public void guide() {
        System.out.println("학생들을 지도한다.");
    }
    public abstract void teach();
}

public class MathTeacher extends Teacher {
    @Override
    public void teach() {
        System.out.println("수학선생님");
    }
}

public interface ClassTeach {
    void classTeach();
    void attendance();
}

public class MathTeacher extends Teacher implements ClassTeach {
    @Override
    public void teach() {
        System.out.println("수학선생님");
    }

    @Override
    public void classTeach() {
        System.out.println("3반 담임선생님");
    }

    @Override
    public void attendance() {
        System.out.println("학생들이 등교를 했는지 출석부를 부른다.");
    }
}

추가

  • 추상클래스의 존재 목적은 추상클래스를 상속받아서 기능을 이용하고 확장시키는 데 있다
  • 인터페이스의 존재 목적은 함수의 껍데기만 가지고 있으면서 함수의 구현을 강제하고 결과적으로 구현 객체의 같은 동작을 보장하기 위함이다.
  • 큰 차이점은 다중상속때문에 인터페이스를 사용하는것 같다…?(그러니깐 추상클래스로 상속받은 서브 클래스는 다른 클래스를 상속받을 수 없지만 , 인터페이스는 다른 여러개의 인터페이스와 함께 구현할 수 있다.) //왤케 어렵노?

추상 클래스

.

  • 포유류는 동물이다.
  • 고래는 포유류다.
  • 고래는 동물이다.

자연스럽게 문장이 이어지는 것을 느낄 수 있을 것입니다. 즉, 상속은 is kind of 관계 입니다.

  • 펭귄 is kind of 동물 -> 펭귄은 동물의 한 분류다.
  • 객체 지향의 상속은 상위 클래스의 특성을 재사용 하는 것입니다.
  • 객체 지향의 상속은 상위 클래스의 특성을 확장하는 것입니다.
  • 객체 지향의 상속은 is kind of 관계를 만족해야 합니다.

인터페이스

인터페이스는 클래스가 무엇을 할 수 있다라고 하는 기능을 구현하도록 강제하는 특징을 가지고 있습니다. 그래서 인터페이스는 extends
키워드가 아니라 implements
키워드를 사용하는 것을 알 수 있습니다. 조금 더 깊이 생각하면 아래와 같이도 생각할 수 있습니다.

SingleTon Pattern

개념

  • 전역 변수를 사용하지 않고 객체를 하나만 생성 하도록 하며, 생성된 객체를 어디에서든지 참조할 수 있도록 하는 패턴

장점

고정된 메모리 영역을 얻으면서 한번의 new로 인스턴스를 사용하기 때문에 메모리 낭비를 방지할 수 있음또한 싱글톤으로 만들어진 클래스의 인스턴스는 전역 인스턴스이기 때문에 다른 클래스의 인스턴스들이 데이터를 공유하기 쉽다.
DBCP(DataBase Connection Pool)처럼 공통된 객체를 여러개 생성해서 사용해야하는 상황에서 많이 사용.(쓰레드풀, 캐시, 대화상자, 사용자 설정, 레지스트리 설정, 로그 기록 객체등)안드로이드 앱 같은 경우 각 액티비티나 클래스별로 주요 클래스들을 일일이 전달하기가 번거롭기 때문에 싱글톤 클래스를 만들어 어디서나 접근하도록 설계하는 것이 편하기 때문

단점

싱글톤 인스턴스가 너무 많은 일을 하거나 많은 데이터를 공유시킬 경우 다른 클래스의 인스턴스들 간에 결합도가 높아져 "개방-폐쇄 원칙" 을 위배하게 된다. (=객체 지향 설계 원칙에 어긋남)
따라서 수정이 어려워지고 테스트하기 어려워진다.

profile
긍정적으로 하루를 살아가자!!

0개의 댓글