[Computer Science] 객체 지향 프로그래밍

in·2023년 10월 5일
0

Computer Science

목록 보기
5/6

📌 객체 지향 프로그래밍

컴퓨터 프로그래밍 패러다임 중 하나로, 프로그래밍에서 필요한 데이터를 추상화시켜 상태와 행위를 가진 객체를 만들고 그 객체들 간의 유기적인 상호작용을 통해 로직을 구성하는 프로그래밍 방법

➡️ 반복될 가능성이 있는 것들을 재사용이 가능한 함수(프로시저)로 만들어 사용하는 프로그래밍 방식

✔️ 프로시저
반환값(리턴)이 따로 존재하지 않는 함수
(printf와 같은 함수는 반환값을 얻는 것이 아닌 화면 출력을 위한 것)

  • 객체 내부에 자료형(필드)와 함수(메소드)가 같이 존재
  • 객체 간의 독립성이 생기고 중복 코드의 양이 줄어듦

장점

  • 코드 재사용 용이
    : 남이 만든 클래스를 가져와서 이용할 수 있고 상속을 통해 확장해서 사용 가능
  • 유지보수가 쉬움
    : 수정해야 할 부분이 클래스 내부에 멤버 변수 혹은 메소드로 존재하기 때문에 해당 부분만 수정하면 됨
  • 대형 프로젝트에 적합
    : 클래스 단위로 모듈화시켜서 개발할 수 있으므로 여러 명이 프로젝트를 개발할 때 업무 분담이 쉬움

단점

  • 처리 속도가 상대적으로 느림
  • 객체가 많으면 용량 증가
  • 설계 시 많은 시간과 노력이 필요

특징

1. 추상화(Abstraction)
: 필요로 하는 속성이나 행동을 추출하는 작업

추상적인 개념에 의존하여 설계해야 유연함을 갖출 수 있다.
즉, 세부적인 사물들의 공통적인 특징을 파악한 후 하나의 집합으러 만들어 내는 것

ex. 아우디, BMW, 벤츠는 모두 자동차라는 공통점이 있다.
자동차라는 추상화 집합을 만들어두고, 자동차들이 가진 공통적인 특징들을 만들어 활용한다.
➡️ 추상화로 구현하면 다른 곳의 코드는 수정할 필요 없이 추가로 만들 부분만 새로 생성하면 된다.

2. 캡슐화(Encapsulation)
: 낮은 결합도를 유지할 수 있도록 설계하는 것
(한 곳에서 변화가 일어나도 다른 곳에 미치는 영향을 최소화 시키는 것)

독립적으로 만들어진 객체들 간의 의존도가 최대한 낮게 만드는 것이 중요하다.

객체 안의 모듈 간 요소가 밀접한 관련이 있는 것으로 구성하여 응집도를 높이고 결합도를 줄여야 요구사항 변경에 대처하는 것이 좋은 설계 방법이다.
➡️ 정보 은닉을 활용하여 높은 응집도와 낮은 결합도 갖도록 함

✔️ 결합도(coupling) : 외부의 모듈과의 연관도 또는 모듈 간의 상호의존성을 나타내는 정도
✔️ 응집도(cohesion) : 모듈의 독립성을 나타내는 개념으로, 모듈 내부 구성요소 간 연관 정도

3. 상속
: 일반화 관계(Generalization)라고도 하며 여러 개체들이 지닌 공통된 특성을 부각시켜 하나의 개념이나 법칙으로 성립하는 과정
(자식 클래스를 외부로부터 은닉하는 캡슐화의 일종)

자식 클래스를 캡슐화해두면, 외부에선 이러한 클래스들에 영향을 받지 않고 개발을 이어갈 수 있는 장점이 있다.

✔️ 상속 재사용의 단점

  • 상위 클래스(부모 클래스)의 변경이 어려워진다.
    부모 클래스에 의존하는 자식 클래스가 많을 때 부모 클래스의 변경이 필요하다면?
    ➡️ 이를 의존하는 자식 클래스들이 영향을 받게 된다.
  • 불필요한 클래스가 증가할 수 있다.
    유사 기능 확장 시, 필요 이상의 불필요한 클래스를 만들어야하는 상황이 발생할 수 있다.
  • 상속이 잘못 사용될 수 있다.
    같은 종류가 아닌 클래스의 구현을 재사용하기 위해 상속을 받게 되면 문제가 발생할 수 있다. 상속 받는 클래스가 부모 클래스와 IS-A 관계가 아닐 때 이에 해당한다.❗️ 해결책
    ➡️ 객체 조립(Composition) 객체조립은 필드에서 다른 객체를 참조하는 방식으로 구현된다. 상속에 비해 비교적 런타임 구조가 복잡해지고, 구현이 어려운 단점이 존재하지만 변경 시 유연함을 확보하는데 장점이 매우 크다. 따라서 같은 종류가 아닌 클래스를 상속하고 싶을 때는 객체 조립을 우선적으로 적용하는 것이 좋다.✔️ 상속은 언제 사용?
  • IS-A 관계가 성립할 때
  • 재사용 관점이 아닌, 기능의 확장 관점일 때

4. 다형성(Polymorphism)
: 서로 다른 클래스의 객체가 같은 메시지를 받았을 때 각자의 방식으로 동작하는 능력
(부모 클래스의 메소드를 자식 클래스가 오버라이딩해서 자신의 역할에 맞게 활용하는 것)

다형성을 사용하면 구체적으로 현재 어던 클래스 객체가 참조되는 지는 무관하게 프로그래밍하는 것이 가능하다.

상속 관계에 있으면 새로운 자식 클래스가 추가되어도 부모 클래스의 함수를 참조해오면 되기 때문에 다른 클래스는 영향을 받지 않게 된다.

오버라이딩(Overriding), 오버로딩(Overloading)이 가능하다.

✔️ 오버라이딩 : 부모클래스의 메서드와 같은 이름, 매개변수를 재정의 하는것
✔️ 오버로딩 : 같은 이름의 함수를 여러개 정의하고, 매개변수의 타입과 개수를 다르게 하여 매개변수에 따라 다르게 호출할 수 있게 하는 것

📌 객체 지향 설계 과정

  • 제공해야 할 기능을 찾고 세분화, 그 기능을 알맞은 객체에 할당

  • 기능을 구현하는데 필요한 데이터를 객체에 추가

  • 그 데이터를 이용하는 기능 넣기

  • 기능은 최대한 캡슐화하여 구현

  • 객체 간에 어떻게 메소드 요청을 주고받을 지 결정

📌 객체 지향 설계 원칙(SOLID)

1. SRP(Single Responsibility) - 단일 책임 원칙
클래스는 단 한 개의 책임을 가져야 한다.

클래스를 변경하는 이유는 단 한개여야 한다.

이를 지키지 않으면 한 책임의 변경에 의해 다른 책임과 관련된 코드에 영향이 갈 수 있다.

2. OCP(Open-Closed) - 개방 폐쇄 원칙
확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다.

기능을 변경하거나 확장할 수 있으면서, 그 기능을 사용하는 코드는 수정하지 않는다.

이를 지키지 않으면 instanceof와 같은 연산자를 사용하거나 다운 캐스팅이 일어난다.

3. LSP(Liskove Substitution) - 리스코브 치환 원칙
상위 타임의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야한다.

상속 관계가 아닌 클래스들을 상속 관계로 설정하면 이 원칙이 위배된다.

4. ISP(Interface Segregation) - 인터페이스 분리 원칙
인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야한다.

각 클라이언트가 필요로하는 인터페이스들을 분리함으로써 각 클라이언트가 사용하지 않는 인터페이스에 변경이 발생하더라도 영향을 받지 않도록 만들어야 한다.

5. DIP(Dependency Inversion) - 의존 역전 원칙
고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다.

저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다.

즉, 저수준 모듈이 변경되어도 고수준 모듈은 변경할 필요가 없는 것이다.

[참고 자료]

🔗링크
🔗링크

0개의 댓글