추상 클래스
추상 클래스를 상속하는 일반 클래스는 반드시 추상 메서드를 구현해야 한다 > 확장
⭐ 하나의 클래스는 추상 클래스와 동시에 인터페이스를 상속 받을 수 있다.
ex)
Animal.java
public abstract class Animal {
public abstract void makeSound();
public void eat() {
System.out.println("eat....done");
}
}
Dog.java
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("makeSound....done");
}
}
Main.java
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
animal.eat();
animal.makeSound();
}
}
인터페이스
클래스가 어떤 메소드를 제공하고, 어떤 상수를 가지는지 정의하는 역할 > 클래스의 골격(명세)을 정의
- 인터페이스를 상속 받은 클래스가 특정한 메서드를 구현하도록 보장
- → 인터페이스를 상속 받은 클래스는 인터페이스의 모든 추상 메서드를 구현해야 한다.
- 인터페이스의 메소드를 overriding 해서 필요한 기능 구현 가능
- 하나의 클래스는 여러 개 인터페이스를 상속 받아 구현할 수 있다
- 디폴트 메소드를 포함할 수 있다. > 구현 클래스에서 따로 구현할 필요 없이 사용 가능
⭐ 클래스 간 결합도를 낮춘다 > 클래스 간 의존성을 낮춘다
인터페이스는 기본적으로 구현 로직을 포함할 수 없지만 default를 명시할 경우 인터페이스에서 로직이 포함된 메서드를 가질 수 있다.
- 디폴트 메소드: 구현 클래스에서 따로 구현할 필요 없이 사용 가능
ex)
(다중 상속) 여러 개 인터페이스를 구현하는 경우, 인스턴스는 구현 클래스로 선언해야 한다.
⭐ 일반적으로 구현 클래스가 아니라 인터페이스로 인스턴스를 선언하는 것이 좋음 > 동일한 동작을 보장, 변화가 없는 것에 의존해라
Shape.java
public interface Shape {
public abstract double calculateArea();
}
Shape2.java
public interface Shape2 {
public abstract double calculatePerimeter();
}
Circle.java
public class Circle implements Shape, Shape2{
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double calculateArea() {
return radius * radius * 3.14;
}
@Override
public double calculatePerimeter() {
return radius * 2 * 3.14;
}
public static void main(String[] args) {
// Shape shape = new Circle(2); // error
Circle shape = new Circle(2);
System.out.println(shape.calculateArea());
System.out.println(shape.calculatePerimeter());
}
}
디폴트 메소드
인터페이스는 기본적으로 구현 로직을 포함할 수 없지만 default를 명시할 경우 인터페이스에서 로직이 포함된 메서드를 가질 수 있다.
인터페이스를 구현하는 클래스는 default method 구현 없이 사용 가능하고, 또는 overriding 해서 사용할 수 있다..
문제:
- 인터페이스 A를 구현하는 많은 클래스가 있을 때, 인터페이스 A에 추상 메서드를 추가해야 하는 경우 모든 클래스가 추가된 추상 메소드를 구현해야 하는 문제 발생
해결:
- default method를 추가해서 추가 구현이 필요 없게 > OCP 유지 (확장에는 open, 변경에는 close)
public interface Interface {
void abstractMethodA();
void abstractMethodB();
default void defaultMehtod() {
// logic
}
}
추상 클래스 vs 인터페이스 차이점 // 중요!
공통점:
- 추상 메소드를 포함
- 상속을 통해 기능을 확장, 다형성을 지원
- 클래스들 간 관계를 나타내는 용도로 사용
차이점:
- 추상 클래스는 추상 메소드 외에 일반 메서드, 인스턴스 변수를 포함할 수 있다. 반면 인터페이스는 추상 메서드, 디폴트 메소드, 정적 메소드, 상수만 가질 수 있다.
- 클래스는 단일 상속, 인터페이스는 다중 상속을 지원
- 클래스가 추상 클래스를 상속받을 때 is-a 관계를 갖는 반면, 인터페이스를 구현할 때 has-a 관계를 갖는다.
- 추상 클래스는 extends 인터페이스는 implements 키워드로 상속한다.
추상 클래스 vs 인터페이스 선택 기준
- 추상 클래스: 클래스 간에 공통 구현을 가지는 경우 / 기본 구현을 제공하고 하위 클래스에서 이를 상속받아 확장하는 경우 / 클래스의 계층 구조가 필요한 경우
- 인터페이스: 다양한 클래스의 공통된 동작을 정의하고 다중 상속이 필요한 경우 / 클래스 간 관계를 느슨하게 결합하고 유연성이 필요한 경우
IS-A vs HAS-A
IS-A A는 B 이다
한 클래스다 다른 클래스의 서브 클래스(파생 클래스)임을 의미한다.
상속 관계에서 클래스가 밀접하게 결합 된다. > 부모 클래스가 변경되면 다른 코드에도 영향을 준다. 대신 설계를 안정적으로 만들어준다.
HAS-A 한 객체가 다른 객체를 (부분적으로) 가진다.
한 오브젝트(객체)가 다른 오브젝트에 속한다.
클래스 간, 객체 간 관계가 느슨하게 결합된다. > 유연성, 상속에 비해서 인터페이스의 변경이 발생해도 구성 요소를 쉽게 변경할 수 있다.
interface 예제
ex)
Shape.java
public interface Shape {
double calculateArea();
double calculatePerimeter();
}
Circle.java
public class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double calculateArea() {
return radius * radius * 3.14;
}
@Override
public double calculatePerimeter() {
return radius * 2 * 3.14;
}
}
Rectangle.java
public class Rectangle implements Shape {
private int width;
private int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public double calculateArea() {
return width * height;
}
@Override
public double calculatePerimeter() {
return width * 2 + height * 2;
}
}
Main.java
public class Main {
public static void main(String[] args) {
Shape rectangle = new Rectangle(5, 10);
Shape circle = new Circle(3.5);
double area1 = rectangle.calculateArea();
double perimeter1 = rectangle.calculatePerimeter();
double area2 = circle.calculateArea();
double perimeter2 = circle.calculatePerimeter();
System.out.println("사각형의 넓이: " + area1);
System.out.println("사각형의 둘레: " + perimeter1);
System.out.println("원의 넓이: " + area2);
System.out.println("원의 둘레: " + perimeter2);
}
}
'CS > Backend' 카테고리의 다른 글
[MySQL] WINDOW 함수 (0) | 2023.05.26 |
---|---|
[MySQL] JOIN (0) | 2023.05.26 |
[Java] Generic, 제네릭 (0) | 2023.05.26 |
[MySQL] EXTRACT(part FROM date) (0) | 2023.05.26 |
[MySQL] 집계 함수, GROUP BY (0) | 2023.05.26 |