[핵심 정리]
일반적으로 다중 구현을 할 때는 인터페이스가 적합하다. 상속은 다중 구현을 금지하기 때문이다.
복잡한 인터페이스라면 골격 구현을 이용해서 수고를 덜어보자
골격 구현의 경우엔 가능한 한 인터페이스의 디폴트 메서드를 제공해 인터페이스를 구현한 모든 곳에서 활용할 수 있도록 하는 것이 좋다.
public abstract class AbstractClass {
private String field1;
void method1() {
}
}
extends
키워드를 사용해 해당 추상 클래스를 기준으로 구현체를 구현할 수 있다.
public interface InterfaceClass {
void method1();
}
implement
키워드를 사용해 해당 인터페이스를 구현할 수 있다.자바8
부터는 인터페이스에서도 제공을 한다. public class BasicClass implements interfaceClass{
//기존 클래스의 멤버들..
//구현하고자 하는 인터페이스의 기능들.. (이미 기존 클래스에 있으면 안 된다)
}
*[기존 클래스에 인터페이스를 구현해 넣은 예시 상황]
[기존 클래스에 추상 클래스를 확장한다면?]
public interface SInger {
}
public interface SongWriter {
Song compose(int chartPosition);
}
public interface SingerSongWriter{
AutoClip sing(Song s);
}
// 골격 인터페이스
interface Recipe {
void cookRecipe(); // 템플릿 메서드
}
// 추상 골격 클래스
abstract class AbstractRecipe implements Recipe {
// 템플릿 메서드 정의
@Override
public void cookRecipe() {
prepareIngredients();
cook();
serve();
}
// 추상 메서드들
protected abstract void prepareIngredients();
protected abstract void cook();
// 기본 구현된 메서드
protected void serve() {
System.out.println("Serve the dish!");
}
}
// 구체적인 레시피 클래스
class PastaRecipe extends AbstractRecipe {
@Override
protected void prepareIngredients() {
System.out.println("Gather pasta, sauce, and cheese.");
}
@Override
protected void cook() {
System.out.println("Boil pasta, add sauce, sprinkle cheese, and cook for 10 minutes.");
}
}
class PancakeRecipe extends AbstractRecipe {
@Override
protected void prepareIngredients() {
System.out.println("Gather flour, eggs, milk, and sugar.");
}
@Override
protected void cook() {
System.out.println("Mix ingredients, pour onto pan, cook each side until golden brown.");
}
}
public class Main {
public static void main(String[] args) {
Recipe pastaRecipe = new PastaRecipe();
pastaRecipe.cookRecipe(); // 템플릿 메서드 호출
System.out.println();
Recipe pancakeRecipe = new PancakeRecipe();
pancakeRecipe.cookRecipe(); // 템플릿 메서드 호출
}
}
인터페이스의 경우엔 다른 인터페이스를 확장하고자 할때 상속 받을 때 사용하는 키워드를 사용해야 한다.