객체지향 주요특징 4가지

객체지향을 공부하며 정리한 포스팅이다. 객체지향의 주요 특징 4가지와 원칙 5가지를 구분하여 2개의 포스팅으로 정리했다.

객체지향 특징 4가지

일반적으로 자바라는 언어를 공부하면 공부하게 되는 4가지 특징들이다.

추상화

추상화는 실제 세상을 객체화하는게 아니라 필요한 정보만을 중심으로 간소화하는것을 의미한다. 실제 지형도보다 지하철역간의 상대위치가 중요하게 정리된 지하철 노선도가 추상화의 대표적인 예이다.

프로그래밍 언어에서는 객체들의 공통적인 속성과 기능을 중심으로 추상화한다.

캡슐화

추상화를 통해 객체를 정의했다면, 객체에 필요한 데이터나 기능(메소드)을 책임이 있는 객체에 그룹화시켜주는 것을 캡슐화(Capsulation)이라 한다.

1
2
3
4
5
6
7
8
9
10
11
public class Lotto {
private List<Integer> lottoNumbers;

public Lotto(List<Integer> lottoNumbers){
this.lottoNumbers = lottoNumbers;
}

public List<Integer> getLottoNumber(){
return lottoNumbers;
}
}

위의 Lotto 클래스는 Lotto와 관련된 정보와 기능만 모아둔 클래스이다. 캡슐화의 예이다.

상속

상위 클래스의 기능을 하위 클래스가 사용할 수 있는 개념이다. 상속이 필요한 이유는 여러 객체에서 사용되는 기능을 하나의 클래스로 분리해서 사용할 수 있도록 위함이다. 즉 중복되는 코드의 재사용성을 위함이다.

1
2
3
class Parent {
int age = 55;
}
1
2
3
4
5
6
7
class Son extends Parent {
private final String name = "Andy";

void parentAge(){
System.out.println(name+" 부모님 나이는 "+age"+세이다.");
}
}
1
2
3
4
5
6
7
class Daughter extends Parent {
private final String name = "Joyce";

void parentAge(){
System.out.println(name+" 부모님 나이는 "+age"+세이다.");
}
}
1
2
3
4
5
6
7
8
9
class App {
public static void main(String[] args){
Son son = new Son();
son.parentAge();

Daughter daughter = new Daughter();
daughter.parentAge();
}
}
1
2
Andy 부모님 나이는 55세이다.
Joyce 부모님 나이는 55세이다.

위의 코드처럼 중복되는 기능이나 데이터는 상위 클래스로 분리하여 상속을 이용하면 재사용할 수 있다.

다형성

객체지향을 공부하면서 위의 특징들을 종합하는, 가장 중요한 특징이라고 생각했던 부분이다. 객체지향은 객체간 관계를 디자인하는 프로그래밍인데, 다형성은 이 객체간 관계를 유연하게 해주는 특징이다.

사람은 음식을 먹는다 라는 명제에서 음식치킨이 될수도 있고, 라면이 될수도 있다. 이 때 음식의 이런 특징을 다형성이라고 한다. 인터페이스가 이런 다형성을 구현할 수 있도록 돕는 대표적인 개념이다.

위에서 사용한 Lotto 클래스를 수정해서 다시 보겠다.

1
2
3
4
5
6
7
8
9
10
11
public class Lotto {
private List<Integer> lottoNumbers;

public Lotto(NumberGenerator numberGenerator){
lottoNumbers = numberGenerator.run();
}

public List<Integer> getLottoNumber(){
return lottoNumbers;
}
}

원래 코드에서 생성자를 수정했다. 기존엔 List<Integer> 타입의 데이터를 직접 넘겨받아서 lottoNumbers를 초기화했다면, 지금은 NumberGenerator라는 객체를 넘겨받아서 이 객체의 내장 메소드를 이용하여 lottoNumbers를 초기화했다.

여기서 생성자인 Lotto()를 보면 파라미터로 NumberGenerator라는 객체를 넘겨받는다. List<Integer> 타입의 데이터를 초기화하는 역할을 하는것으로 보아 로또 숫자를 실제 생성하는 코드일것 같다.

이때 사용한 NumberGenerator는 아래처럼 구현할 수 있다.

1
2
3
interface NumberGenerator {
public List<Integer> run();
}

클래스가 아닌 인터페이스로 생성함으로써 실제 구현을 하위 객체로 넘길수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class LottoNumberGenerator implements NumberGenerator {
@Override
public List<Integer> run(){
List<Integer> temp = new ArrayList<>();
for(int i=1; i<=45; i++){
temp.add(i);
}
Collections.shuffle(temp);

List<Integer> lotto = new ArrayList<>();
for(int i=0; i<6; i++){
lotto.add(temp.get(i));
}
return lotto;
}
}

실제 로또 번호를 생성하는 코드는 NumberGenerator 구현체인 LottoNumberGenerator로 구현했다.

Lotto 클래스의 의존관계는 아래와 같다.

Lotto 클래스는 NumberGenerator를 의존하지만, NumberGenerator는 인터페이스이므로 로또번호를 생성하는 로직 또는 클래스가 변경되더라도 Lotto 클래스의 코드는 건드릴 필요가 없다. LottoNumberGenerator만 바꾸면 된다.

다음 포스팅 객체지향 주요원칙 5가지 읽으러가기.