공통의 속성이나 기능을 묶어 이름을 붙이는 것, 객체 지향 관점에서 클래스를 정의 하는 것을 추상화라고 할 수 있습니다.
추상화가 안된 객체지향적이지 않은 코드를 보겠습니다.
public class Client {
public void SomeMethod() {
FakeMessageSender fakeMessageSender = new FakeMessageSender();
fakeMessageSender.send();
}
}
class RealMessageSender {
public void send() {
// 실제 메시지 보내는 기능
}
}
class FakeMessageSender {
public void send() {
// 메시지는 안 보내고 메시지를 보냈다는 로그 찍기
}
}
위 코드는 Client가 메시지를 보내는 기능을 테스트, 또는 실제 메시지를 보내는 것을 구현한 것입니다. Client 가 해당 기능들을 사용하려면 직접 객체를 생성하여 메서드를 호출해야 합니다.
FakeMessageSender의 send메서드를 사용하다가 RealMessageSender의 send 메서드를 사용하려고 한다면 Client의 코드가 변경되어야 합니다.
public class Client {
private final MessageSender messageSender;
Client(MessageSender messageSender) {
this.messageSender = messageSender;
}
public void SomeMethod() {
messageSender.send();
}
}
interface MessageSender {
void send();
}
class RealMessageSender implements MessageSender{
public void send() {
// 실제 메시지 보내는 기능
}
}
class FakeMessageSender implements MessageSender{
public void send() {
// 메시지는 안 보내고 메시지를 보냈다는 로그 찍기
}
}
인터페이스를 사용하여 Client는 더 이상 FakeMessageSender와 RealMessageSender에 의존적이지 않습니다. MessageSender는 다형성을 제공해주는 추상적인 존재이고 저희는 가급적 인터페이스 같은 추상적인 존재에 의존하도록 코드를 작성해야 합니다.
public abstract class AbstractClass {
public void implementedMethod() {
System.out.println("AbstractClass implementedMethod");
this.abstractMethod();
}
abstract public void abstractMethod();
}
class ExtendedClass extends AbstractClass {
@Override
public void abstractMethod() {
System.out.println("ExtendedClass abstractMethod");
}
}
추상 클래스는 인스턴스를 생성할 수 없습니다.
일반적으로 하나 이상의 추상 메서드를 포함합니다.
추상 클래스에 구현된 메서드 안에서 구현되지 않은 abstract 메서드를 호출할 수 있다는 점을 확인 할 수 있습니다. 이 문법은 강력한 추상화 문법입니다.
공통된 로직은 추상 클래스에 미리 정의해두고 각각의 구현 클래스에서 달라져야 하는 부분만 abstract 메서드를 구현하여 사용할 수 있습니다.
interface SomeInterface {
void someMethod();
default void defaultMethod() {
this.someMethod();
}
}
interface AnotherInterface {
void anotherMethod();
}
class ImplementsClass implements SomeInterface, AnotherInterface {
@Override
public void someMethod() {
System.out.println("someMethod");
}
@Override
public void anotherMethod() {
System.out.println("anotherMethod");
}
}
클래스는 하나만 상속 받을 수 있습니다.
인터페이스는 여러 개 구현이 가능합니다.
인터페이스를 구현하는 클래스는 해당 인터페이스가 가지고 있던 메서드를 반드시 구현해야 합니다.
인터페이스에서 메서드 앞에 default 키워드를 넣게 되면 default 메서드입니다. default 메서드는 인터페이스에도 메서드를 정의할 수 있게 해줍니다. (JAVA8 이후 가능)
문법적으로는 비슷하다 할 수 있지만 사용하는 상황이 다릅니다.
이런 경우를 제외하면 대부분의 경우 interface를 사용하는 것이 더 바람직합니다. 인터페이스는 추상 클래스보다 더 추상적인 존재이기 때문입니다.
해당 게시글은 프로그래머스 스쿨 강의
"실무 자바 개발을 위한 OOP와 핵심 디자인 패턴(푸)"
를 정리한 내용입니다. 쉽게 잘 설명해주시니 여러분도 강의를 듣는 것을 추천드립니다.