Spring, Java 에 관해서 알게된 것들 1

정환우·2022년 3월 27일
1

스프링

목록 보기
3/9
post-thumbnail
post-custom-banner

김영한님의 스프링 강의를 들으면서 궁금했던 것들, 자바 문법을 처음 접하면서 신기하거나 궁금했던 것들에 대해서 정리해 보려고 한다.

Interface와 Absract class

우선 김영한님의 강의를 듣다보면, 객체지향적인 설계에 초점을 맞추시는 것을 볼 수 있다.
그에 따라서 코드 또한 객체지향적으로 설계를 하시면서, 응집도와 결합도를 중요시 다루는 것을 볼 수 있다.
과연 그렇다면 응집도와 결합도는 무엇일까?

  • 결합도(Coupling) : 모듈 간에 상호 의존하는 정도, 연관된 관계이다. 결합도가 높은 클래스는 해당 클래스를 변경하게 되면 그와 연관된 다른 클래스도 변경해야 하고, 재사용이 어렵다.
  • 응집도(Cohesion) : 모듈이 독립적인 기능을 수행하는 지, 하나의 기능이 중심이 되어있는 지를 나타낸다. 높은 응집도를 가질수록 좋다.

여기서 말하는 모듈은 기능별로 나눠진 것을 모듈이라고 하며, 이렇게 소프트웨어를 각 기능(모듈)로 나누는 것을 모듈화라고 한다.

이 정도로 응집도와 결합도에 대한 배경지식을 정리하였다.

강의를 듣다보면 RepositoryService를 Interface를 구현시키거나 추상 클래스를 상속받아 사용하는 경우가 많은데, 왜 그렇게 하는 것이며 둘이 무슨 차이가 있는지 조금 알아보려고 한다.

Abstract class

  • abstractfinal 키워드는 동시에 사용 불가능하다. 클래스 내에 단 한개의 추상메소드(구현되어 있지 않은 abstract 메소드)가 존재한다면 반드시 abstract class로 선언해야 한다.
  • 추상클래스도 일반적인 메소드, 일반적인 변수를 가질 수 있다. 추상클래스에서 상속을 받으면 구현하지 않아도 되지만, 추상클래스가 아닌 클래스에서 추상클래스를 상속받으면 추상메소드를 모두 구현해줘야 한다.
  • 생성자를 가질 수 있다. 추상클래스는 인스턴스를 만들 수 없지만 이 클래스를 상속받은 클래스를 통해서 만들 수 있다.
  • 추상클래스를 상속받을 때는 extend 를 쓴다.
public abstract class AbstractClass {
	public abstract void exampleMethod();
    
    public void normalMethod(){
    	System.out.println("일반적인 메소드 입니다.");
    }
}

public class ExClass extends Abstractclass {
	@Override
    public void exampleMethod(){
    	System.out.println("추상 클래스의 추상 메소드를 구현했습니다.");
    }
 }

Interface

  • 비어있는 메소드들의 형태만 써놓은 것이며, 상속받은 클래스들이 해당 메소드의 내용을 구현해야 한다.
  • 상속받은 클래스들이 구현해야하는 메소드의 집합이라고 볼 수도 있겠다.
  • final을 붙일 수 없고 변수들은 static 이어야만 한다.

결론

  • 공통점 : 둘 다 추상 메소드를 사용할 수 있다.
  • 추상클래스가 지원하는 기능이 인터페이스를 포함해서 더 포괄적으로 지원하는 것 같은데, 왜 인터페이스를 사용할까? -> 가장 결정적인 이유는 클래스는 한 개만 상속 가능, 인터페이스는 여러 개 구현 가능이다.

그래서 추상클래스와 인터페이스는 사용 용도가 구분이 된다. 추상클래스는 대상의 속성을, 인터페이스는 대상의 기능을 표현할 때 사용하는 것으로 말이다.

  • 추상클래스는 공통된 개념을 표현할 때 쓴다고 한다. 그러니까 예를 들면 말, 사자, 호랑이는 피부색이 있고 이름이 있고 달리는 동물들이니까, 동물이라는 속성을 추상 클래스로 만들고 달린다는 것을 추상 메소드로 만든다음, 말이라는 객체에 상속시켜서 구현하면 객체의 재사용성이 높아지고 표현하는 것이 더 명확해진다. 말은 달리는 속도가 빠르고 강아지느 느리니까, 달리기를 구현할 때 이 둘의 차이를 둘 수가 있다.

  • 인터페이스는 구성하는 요소들이 자주 바뀔 때 사용하면 유용하다고 한다. 메소드들의 내용은 몰라도 결과값은 미리 알 수 있으니까, 메소드 형태만 서로 공유하여 구현하는 상황일 때 적합하다고 한다.

100% 이해는 안되지만, 어느정도 구분이 가는 것 같다.

final vs static final

이것도 항상 쓸때마다 제대로 알고 쓰는게 아니어서 궁금했다. 제대로 알고 써보자.

final

먼저 final 키워드는 상수, 메소드, 클래스 이렇게 3가지 경우에 사용이 가능하다고 한다.

상수에 쓰이는 경우

  • 상수에 값을 한번 저장하고 다음에 다시 바꾸고 싶지 않을 때 사용한다.

final int ex;
ex = 3;

ex = 5; // 오류

메소드에 쓰이는 경우

  • 오버라이딩을 할 수 없게 만든다.

클래스에 사용하는 경우

  • 상속을 할 수 없다.

final은 이처럼 값을 바꾸고 싶지 않을 때 사용하는 것이라고 이해를 하면 되겠다.
상수에 선언하면 상수의 값을 바꿀 수 없고, 메소드에 선언하면 오버라이딩을 할 수 없고, 클래스에 선언하면 상속을 할 수 없어 내용을 변경할 수 없는 것이다.

static final

그렇다면 static final은 무엇일까? 앞서 사용한 final 개념에 static을 추가한 것이다.
즉, 객체마다 존재하는 인스턴스가 아니라, 클래스에 존재하는 단 하나의 상수이다.

그러니까, 클래스를 여러개 선언해도 클래스에 존재하는 단 하나의 상수이므로, 값이 당연히 변경이 안될 것이며, 선언과 동시에 무조건 초기화를 해줘야 하는 클래스 상수인 것이다.

그러니까..음..final a = 3을 모든 클래스 마다 해준다면 static final int a = 3이 되는 것이 되는 것일까 라는 의문이 든다.

아마도 그게 맞는 것이라고 생각이 드는게, 실제로 우리가 lombok을 사용하여 private static final 객체를 private final 에 @RequiredArgsConstructor를 사용하는 방식으로 바꿔서 사용하는 것을 보면, 어느정도 맞는 것 같다.

Reference

[JAVA] 추상클래스 VS 인터페이스 왜 사용할까? 차이점, 예제로 확인 :: 마이자몽

profile
Hongik CE
post-custom-banner

0개의 댓글