[JAVA의 정석] 객체지향 프로그래밍 - 추상클래스, 인터페이스

etlaou·2021년 7월 24일
0

💡추상클래스

미완성 설계도
틀(리턴값, 매개변수 등)만 잡아두고 상속받는 자손클래스가 오버라이딩 하는 것

추상클래스는 미완성이기 때문에 인스턴스를 생성할 수 없으며, 자손 클래스에 의해 완성될 수 있다.
추상클래스 자체만으로는 클래스 역할을 다 하지는 못하지만, 새로운 클래스를 작성하는데 있어서 바탕이 되는 조상클래스로서 중요한 역할을 한다.

  • 추상클래스를 왜 사용할까?
    : 우리가 어떤 것을 만들 때 어느정도 설계된 상태에서 시작하는 것이 효율적이기 때문에, 공통부분만을 틀을 잡아 놓고 이를 이용해 설계를 완성하는 것이 효율적이다.
abstract class 클래스 이름 {
	// ...
}

추상클래스는 추상메서드를 포함하는 것을 제외하고는 일반 클래스와 다르지 않다. 생성자도 있고 멤버 변수도 가질 수 있다.

추상메서드

선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것
설계만 해놓고 실제 수행 내용은 작성하지 않은 메서드

  • 추상메서드 사용 이유
    : 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있기 때문에 선언부만 작성하고 어떤 기능을 수행할 목적으로 작성되었는지 알려준다.
abstract 리턴타입 메서드이름();

추상클래스로 부터 상속받는 자손클래스는 오버라이딩을 통해 조상인 추상클래스의 추상 메서드를 모두 구현해야한다.

만일 조상으로 부터 상속받은 추상메서드 중 하나라도 구현하지 않을 경우, 자손클래스 역시 추상클래스로 지정해야한다.

AudioPlayer 클래스는 조상의 추상메서드 모두를 오버라이딩 했지만
AbstractPlayer 클래스는 play 추상메서드만 오버라이딩 했기때문에 Abstract로 지정해야한다.

추상클래스 작성

추상화: 클래스간의 공통점을 찾아내서 공통의 조상을 만드는 작업
구체화: 상속을 통해 클래스를 구현, 확장하는 작업

상속계층도를 따라 내려갈수록 클래스는 점점 기능이 추가되어 구체화의 정도가 심해지며, 번대로 올라갈수록 클래스는 추상화 정도가 심해진다. → 내려갈수록 "세분화", 올라갈수록 "공통요소"만 남는다.

  • Abstract 키워드를 어떻게 쓸까?
    : 자손 클래스에서 추상메서드를 반드시 구현하도록 강요할 때 사용한다.
    만약 추상메서드로 정의되어 있지 않는다면, 상속받는 자손클래스에서는 이 메서드를 온전히 구현된 것으로 인지하고 오버라이딩을 통해 자신의 클래스에 맞도록 구현하지 않을 수도 있기 때문이다.
    하지만 abstrat로 추상메서드를 정의한다면, 자손 클래스 작성시 이 추상메서드로 내용을 구현해주어야 한다는 사실을 인식하고 클래스에 맞게 구현할 것이다.

💡인터페이스

인터페이스를 공부할 때는 추상클래스와 비교하면서 공부할 필요가 있다

인터페이스는 일종의 추상클래스 이다.
하지만 차이가 있다. 인터페이스는 추상클래스보다 추상화 정도가 강해서(진짜 완전 틀만 있다.) 몸통을 갖춘 일반 메서드 또는 멤버변수를 가질 수 없다. 오로지 추상메서드와 상수만을 가질 수 있다.

[추상클래스] : 미완성 설계도
[인터페이스] : 기본 설계도
→ 인터페이스도 미완성이기 때문에, 이를 사용해서 무엇을 한다기 보다는 다른 클래스를 작성하는데 필요한 요소이다.

인터페이스 작성

: 클래스 작성법과 같으나, interface 키워드 사용

interface 인터페이스이름{
	public static final 타입 상수이름 =;
	public abstract 매서드이름(매게변수);
}

모든 멤버변수는 public static final, 모든 메서드는 public abstrat이다. (생략가능)

인터페이스 상속

  1. 인터페이스는 인터페이스로부터만 상속 가능하다.
  2. 클래스와 달리 다중상속이 가능하다.
  3. 클래스와 같이 조상의 멤버를 모두 상속 받는다.
interface Movable{
	void move (int x, int y); // public abstract 생략된 것
}

interface Attackable {
	void attack(Unit u);
}

interface Fightable extends Movable, Attackable{ //다중 상속
}  

인터페이스 구현 (implements)

인터페이스 다중상속

다중상속의 단점으로 동일한 이름의 멤버변수 또는 메서드 선언부가 있을 경우 어떤 클래스의 것을 상속받을지 알 수가 없다. 그래서 자바는 다중상속을 허용하지 않지만 인터페이스는 가능하다. 그래서 사람들이 인터페이스로 다중상속을 할 수 있는 것을 알고 있지만, 인터페이스로 다중상속을 구현하지는 않는다.

만약 두 개의 클래스로부터 상속을 받아야 하는 상황이라면, 하나를 상속하고 나머지는 클래스 내부에 멤버로 포함시키는 방식으로 처리하거나 인터페이스로 만드는 방식을 사용한다.
→ 하나의 클래스를 상속받고 다른 클래스는 클래스 내부에 포함시켜 내부럭으로 인스턴 생성해서 사용한다.

인터페이스 다형성

리턴타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한
클래스의 인스턴스를 반환하다느 것을 의미

인터페이스 장점

  1. 개발시간을 단축시킬 수 있다.
    : 인터페이스를 이용해 프로그램을 작성할 수 있고, 동시에 다른 한 쪽에서 인터페이스를 구현하는 클래스를 자겅하게 되면 인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고도 동시에 개발이 가능

  2. 표준화가 가능하다.
    : 일관되고 정형화된 프로그램 개발 가능 (같은 기본 틀을 사용하기 때문에)

  3. 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
    : 서로 상속 관계가 없는 클래스들 간에 하나의 인터페이스를 공통적으로 구현하도록 하여 관계를 형성할 수 있다.

  4. 독립적인 프로그래밍이 가능하다.
    : 인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제 구현에 독립적인 프로그램을 작성하는 것이 가능하다. 직접적인 관계를 인터페이스를 이용하여 간접적인 관계로 변경하면, 하나의 클래스가 변경되더라도 다른 클래스에 영향을 미치지 않는 독립 프로그래밍이 가능하다.

인터페이스의 이해

[본질적인 이해]

클래스를 사용하는 쪽(User)과 클래스를 제공하는 쪽(Provider)이 있다.
메서드를 사용하는 쪽에서는 사용하려는 메서드의 선언부만 알면된다.

  • 클래스를 사용하는 쪽과 클래스를 제공하는 쪽이 있다.
    : User와 Provider가 직접적인 관계일 때, User가 사용하려면 Provider가 이미 작성이 되어 있는 상태여야 하고, Provider가 변경되면 User도 변경되는 단점이 있다.

하지만 인터페이스를 사용하여 간접적인 관계를 바꿔주면서, 인터페이스를 매게체로 하여 서로 영향을 주지 않도록 분리할 수 있다.

클래스 A는 클래스 B,C의 메서드를 호출하지만, 인터페이스 I를 통한 간접적인 관계를 맺으므로써 서로에게 영향을 주지 않는다.


인스턴스를 직접 생성하지 않고, getInstance() 메서드를 통해 제공받는다. 이렇게 하면 다른 클래스의 인스턴스로 변경되어도 A 클래스를 변경할 필요가 없다.

디폴트 메서드와 static 메서드

JDK1.8부터는 추상메서드 이외에도 디폴트메서드와 static 메서드를 추가할 수 있다.

[디폴트메서드]
: 조상 클래스에 새로운 메서드를 추가하는 것을 별일이 아니다. 하지만 인터페이스에 새로운 추상메서드를 추가한다는 것은 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야한다.
→ 이를 해결하기 위해 디폴트 메서드가 생겼다. 추상메서드가 아니기 때문에 새로 추가되어도 해당 인터페이스로 구현한 클래스를 수정할 필요가 없다.

  1. 여러 인터페이스의 디폴트 메서드 간의 충돌
    : 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩 해야한다.
  2. 디폴트 메서드와 조상클래스의 메서드 간의 충돌
    : 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.

profile
To be Cloud DevOps Engineer

0개의 댓글