거누의 개발노트

객체지향(Object Oriented Programming) 정리 본문

CS

객체지향(Object Oriented Programming) 정리

Gogozzi 2022. 6. 7. 11:15
반응형

면접에서 꼭 질문하는 꼬리에 꼬리를 무는 객체지향에대해서 공부해 보려고 한다.

객체 지향 프로그래밍(Object Oriented Programming)

먼저 객체란 우리가 실생활에서 쓰는 모든 것을 객체라고 한다.

간단한 예로 선풍기, 노트북 주변에 있는 모든것들이 객체가 될 수 있다. 사물뿐만 아니라 동물, 사람도 마찬가지로 객체가 될 수 있는 것이다.

그래서 객체 지향 프로그래밍은 먼저 객체를 파악하고, 이 객체들이 무슨 역할을 하는지 정의하여 객체들 간의 상호작용을 통해 프로그램을 만드는 것을 말한다.

결론, 필요한 데이터를 추상화 시켜서 상태와 행위를 가진 객체를 만들고 그 객체들간의 상호작용을 통해 로직을 구성하는 방법론인거다.

추상화

그럼 추상화시킨다는 말은 어떤 의미일까?

공통의 속성이나 기능을 묶어서 이름을 붙이는것을 의미한다고 한다.

예를 들어 토끼, 사자, 기린이 있을 때 우리는 이러한 아이들을 공통적으로 동물이라고 부른다.

그리고 동물들은 각각 공통의 속성들을 가지고 있을 것이다. 예를들어 키나, 몸무게, 달리기 등과 같이 말이다.

아래는 간단하게 예를들어 보았다.

토끼랑 거북이에 대해서 공통속성인 이름과 속도를 묶었고, 달리기라는 메소드를 정의해 놓았다.

public abstract class Animal {
    String name;
    int speed;

    Animal(String name, int speed){
        this.name = name;
        this.speed = speed;
    }

    abstract void run();

}
public class Turtle extends Animal {

    Turtle(String name, int speed) {
        super(name, speed);
    }

    @Override
    void run() {
        System.out.println(this.name+"는 "+speed+"의 속도로 달린다.");
    }
}
public class Rabbit extends Animal {
    Rabbit(String name, int speed) {
        super(name, speed);
    }

    @Override
    void run() {
        System.out.println(this.name+"는 "+speed+"의 속도로 달린다.");
    }
}
public class Match {

    public static void main(String[] args) {
        Rabbit rabbit = new Rabbit("토끼", 5);
        Turtle turtle = new Turtle("거북이", 1);

        rabbit.run();
        turtle.run();
    }
}

동물이라는 객체로 추상화해서 공통의 속성이나 메소드를 묶어서 이름을 붙여 놓았다.

속성들을 재정의 할 필요가 없어졌고 메소드도 통일감있게 작성할 수 있게 되었다.

결론적으로 추상화를 하는 이유는 중복코드가 줄고  코드의 재사용성이 증가하기 때문에 추상화를 하는 목적이 된다.

상속

동물이라는 객체를 상속받았는데 이번에는 상속이라는 개념을 알아보자! :)

상위 개념의 특징을 하위 개념이 물려받는 것이 상속이다! (우리가 알고있는 개념과 같다.)

사실 위에 있는 코드에 상속이라는 개념이 들어가있다.

동물(Animal)객체가  상위 개념이고 거북이와 토끼가 속성들을 물려 받은 것이다. - (extends)

public class Rabbit extends Animal {
    Rabbit(String name, int speed) {
        super(name, speed);
    }

    @Override
    void run() {
        System.out.println(this.name+"는 "+speed+"의 속도로 달린다.");
    }
}

 

추상화를 한 뒤에는 상속이라는 개념이 따라 올 수 밖에 없는것같다.

열심히 추상화를 했지만 묶어놓은 기능을 사용하려면 결국 상속을 받아서 사용해야 하는 것이다.

상속은 예제와 같이 속성이나 메서드를 재사용한다. 이로 인해 코드가 줄어든다!

캡슐화

캡슐화는 실제로 구현되는 부분을 외부에 드러나지 않도록 캡슐로 감싸 이용방법만을 알려주는것이다.

그래서 메소드(이용방법)만 접근가능하고 속성값들은 접근할 수 없다.

간단하게 코드로 작성해보면

public class Turtle extends Animal {

    private int hungry = 10;

    Turtle(String name, int speed) {
        super(name, speed);
    }

    @Override
    void run() {
        System.out.println(this.name+"는 "+speed+"의 속도로 달린다.");
        hungry(); // 달렸더니 허기가 지는군요.
    }

    public void hungry(){
        hungry++;
        System.out.println("열심히 달렸더니 허기가 지군요.");
    }

    public void eat(){
        hungry--;
        System.out.println(name+" 이(가) 밥을먹어서 배고픔 지수가 " +this.hungry+"가 되었습니다.");
    }

    public void status(){
        System.out.println(name+"의 배고픔 지수는 " +this.hungry+" 입니다.");
    }

}
public class Match {

    public static void main(String[] args) {
        Turtle turtle = new Turtle("거북이", 1);

        turtle.status();
        turtle.run();
        turtle.status();
        turtle.eat();
        turtle.status();
    }
}

//거북이의 배고픔 지수는 10 입니다.
//거북이는 1의 속도로 달린다.
//열심히 달렸더니 허기가 지군요.
//거북이의 배고픔 지수는 11 입니다.
//거북이 이(가) 밥을먹어서 배고픔 지수가 10가 되었습니다.
//거북이의 배고픔 지수는 10 입니다.

거북이의 배고픔은 거북이 스스로 관리하면 되는것이다.

다른 코드에서 거북이의 배고픔을 조절한다면 거북이 객체는 혼선이 올것이다.

배고픈데 배고픈게 아닌게되는? 밥을 먹어야하는데 허기짐지수가 높아서 밥을 먹어야 하는 상황이 오지 않는 오류가 생기는 것이다.

이렇듯 함수 중심적인 구조적 프로그래밍 언어에서는 프로그램 내부에서 데이터가 어디서 어떻게 변경되는지 파악하기 어려웠다.

그로 인해 유지보수가 어려웠지만 객체지향에서는 캡슐화를 통해서 유지보수성이 향상된 것이다!

Getter & Setter

우리는 private로 멤버변수의 접근을 제한했지만 public 메서드로 Getter나 Setter를 만들었다.

이렇게 하면 어디서든 접근이 가능한데 굳이 이렇게하는 이유를 잘 모르고있었다.

하지만 이유는 간단하다.

Getter나 Setter메소드로 접근하기 때문에, 올바르지 않은 예를 들어 타입을 맞추지 못했거나, 유효성을 통과하지 못할 데이터가 들어온다면 메소드를 통해서 사전에 처리할 수 있게 제한하거나 조절할 수 있기 때문이다.

클래스와 인스턴스

사실 우리는 매일 같이 클래스와 인스턴스를 보면서도 정확히 이게 머라고 말하기 어려울 것이다.

오늘부터는 확실히 설명할 수 있어야한다.

클래스(Class)는 간단히 객체를 만들기 위한 틀 또는 설계도라고 생각하면 쉽다.

인스턴스는 설계도를 바탕으로 소프트웨어 세계에 구현된 구체적인 실체

우리는 설계도를 작성하고 그걸 바탕으로 소프트웨어에서 사용가능한 구체적인 실체를 만들어내는 셈인거다.

다형성

웹사전에 따르면, 다형성의 일반적인 의미는 '다양한 형태로 나타날 수 있는 능력'이라고 한다.

다형성은 하나의 변수명, 함수명 등이 상황에 따라 다른 의미로 해석될 수 있는 것을 말한다.

위에 예시들에서 토끼와 거북이는 동물이라는 객체의 속성과 메소드를 상속받았다.

그중에 run()라는 메소드를 재정의 해서 사용했는데, 이 부분을 오버라이딩이라고 한다.

오버로딩이라는 개념은 같은 이름 함수를 여러개 정의하고, 매개변수의 타입과 개수를 다르게 하여 매개변수에 따라 다르게 호출할 수 있게 하는 것을 의미한다.

public class Run {
    static public void hungry(){
        System.out.println("열심히 달렸더니 허기가 지군요.");
    }
    static public void hungry(String name){
        System.out.println(name+"이 열심히 달렸더니 허기가 지군요.");
    }
    static public void hungry(String name, int hungry){
        System.out.println(name+"이 열심히 달렸더니 허기가 지군요. "+hungry+"만큼 배가 고파요!");
    }

    public static void main(String[] args) {
        hungry();
        hungry("토끼");
        hungry("토끼", 100);
    }
}

 

위 코드 처럼 메소드명은 같지만 매개변수 타입이나 개수를 변경하여 매개변수에 따라 다르게 호출하고 있다.

 

객체지향하면 빠질 수 없는 키워드인 추상화, 상속, 캡슐화, 클래스와 인터페이스 그리고 다형성에 대해서 알아보았다.

이러한 키워드로 인해서 우리는 객체지향의 장단점을 알 수 있게 되었다.

장점

1. 코드를 재사용할 수 있다.

  • 남이 만든 클래스를 가져와서 이용할 수 있고 상속을 통해 확장해서 사용할 수 있다.

2. 유지보수가 쉽다.

  • 절차 지향 프로그래밍에서는 코드를 수정해야할 때 일일이 찾아 수정해야하는 반면 객체 지향 프로그래밍에서는 수정해야 할 부분이 클래스 내부에 멤버 변수혹은 메서드로 존재하기 때문에 해당 부분만 수정하면 된다. 

3. 대향 프로젝트에 적합하다.

  • 클래스 단위로 모듈화시켜서 개발할 수 있으므로 대형 프로젝트처럼 여러 명, 여러 회사에서 프로젝트를 개발할 때 업무 분담하기 쉽다.

단점

1. 처리 속도가 상대적으로 느리다.

2. 객체가 많으면 용량이 커질 수 있다.

3. 설계시 많은 시간과 노력이 필요하다.

반응형
Comments