본문 바로가기
프로그래밍/스프링 자바

객체 지향 프로그래밍이 정리 (OOP 정리)

by 커피는아아 2021. 6. 28.
반응형

OOP

1. 객체지향 프로그래밍은 무엇인가?

  • 객체 지향 프로그래밍은 어떤 속성과 동작을 가진 객체를 만들고, 객체들을 조립하여 하나의 프로그램을(상호작용을 하는) 만드는 방법을 객체지향 프로그래밍이라 한다.

2. 객체 프로그래밍의 장,단점 설명

  • 장점
    • 코드 재사용이 용이하다.
      • 남이 만든 클래스를 가져와서 이용할 수 있고 상속을 통해 확장할 수 도 있다.
    • 유지보수가 쉽다.
      • 절차 지향 프로그래밍에서는 코드를 수정해야할 때 일일이 찾아 수정해야 하는 반면 객체 지향 프로그래밍은 수정해야 할 부분이 클래스 내부의 멤버 변수혹은 메서드로 있기 때문에 해당 부분만 수정하면 됨
    • 프로그램을 유연하고 변경 용이하게 만든다.
  • 단점
    • 처리속도가 상대적으로 느림
    • 객체가 많으면 용량이 커질 수 있음
    • 설계시 시간과 노력이 필요

3. 객체지향의 특징

  • 추상화
  • 캡슐화
  • 상속
  • 다형성 (핵심)

4. 클래스와 인스턴스(객체)는 무엇인지 설명해주세요

  • 클래스는 객체를 정의하는 설계도를 말한다.
  • 객체는 클래스에서 정의한 것을 토대로 실제 메모리상에 할당 된 것으로 실제 프로그램에서 사용하는 데이터이다.

5. 추상화란?

  • 객체들의 공통적인 속성과 기능을 뽑아내는 작업, 즉 우리가 구현하는 객체들이 가진 공통적인 데이터와 기능을 묶어 이름을 붙이는 것을 말한다.

6. 캡슐화란?

  • 연관있는 속성과 기능을 클래스로 묶는 작업을 말한다.
  • 캡슐화는 은닉성을 통해 클래스에 담는 중요한 데이터나 기능을 외부에서 접근하지 못하게 할 수 있다.
  • 자바 언어는 캡슐화된 멤버를 노출시킬 것인지 숨길 것인지를 결정하기 위해 접근 제한자를 사용한다.

7. 상속이란?

  • 부모클래스의 속성과 기능을 그대로 이어받아 사용할 수 있게하고 기능의 일부분을 변경해야 할 경우 상속받은 자식클래스에서 해당 기능만 다시 수정(정의)하여 사용할 수 있게 하는 것이다.
  • 상속 받은 것을 자식클래스에서 다시 재정의 해서 사용하는 다형성과도 이어져있다.

8. 다형성이란?

  • 객체를 설계할 때 역할과 구현을 명확히 분리
  • 같은 역할이라도 구현된 것에 따라 그 결과가 다르게 발현되는 것을 말한다.
    • 오버라이딩 (인터페이스, 상속)
    • 오버로딩
  • 자바 언어의 다형성을 활용
    • 역할 = 인터페이스
    • 구현 = 인터페이스를 구현한 객체
    • 객체를 설계할 때 역할과 구현을 명확히 분리
    • 객체 셜계시 역할(인터페이스)을 먼저 부여하고, 그 역할을 수행하는 구현 객체 만들기
  • 다형성의 본질
    • 다형성으로 인터페이스를 구현한 객체를 실행 시점에 유연하게 변경할 수 있다.

9. 좋은 객체지향 프로그래밍이란 무엇인가?

  • 모든 설계에 역할구현을 분리하여 언제든지 유연하게 변경할 수 있도록 만드는 것이 좋은 객체 지향 설계이다.
    • 키보드, 마우스 갈아 끼우듯이, 컴퓨터 부품 갈아 끼우듯이
  • 역할과 구현을 분리하면?
    • 유연하고 변경이 용이
    • 확장 가능한 설계
    • 클라이언트에 영향을 주지 않고 변경가능
    • 인터페이스를 안정적으로 잘 설계하는 것이 중요
      • 인터페이스 자체가 바뀌면 모든 것이 변한다.

10. SOLID란?

[ 좋은 객체 지향 설계를 하기 위한 5가지 원칙을 말한다]

  • SRP : 단일 책임 원칙 (Single Responsibility Principle)
  • OCP : 개방-폐쇄 원칙 (Open-Closed Principle)
  • LSP : 리스코프 치환 원칙 (Liskov Subsitution Principle)
  • ISP : 인터페이스 분리 원칙 (Interface Segregation Principle)
  • DIP : 의존관계 역전 원칙 (Dependency Inversion Principle)

(1) 단일 책임 원칙 (SRP : Single Responsibility Principle)

  • 한 클래스는 하나의 책임만 가져야 한다.
  • 하나의 책임이라는 것은 모호하다.
    • 클 수 있고, 작을 수 있다.
    • 문맥과 상황에 따라 다르다.
  • 중요한 기준은 변경이다. 변경이 있을 때 파급 효과(하나의 지점만 고치면)가 적으면 단일 책임 원칙을 잘 따른 것
  • 예) UI 변경, 객체의 생성과 사용을 분리

(2) 개방-폐쇄 원칙 (OCP : Open-Closed Principle)

  • 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
  • 다형성을 활용해보자.
  • 인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현

[ 문제점 ]

기존 코드

public class MemberService {

    private MemberRepository memberRepository = new MemoryMemberRepository();
}

변경 코드

public class MemberService {

    // private MemberRepository memberRepository = new MemoryMemberRepository();
    private MemberRepository memberRepository = new JdbcMemberRepository();
}
  • MemberService 클라이언트가 구현 클래스를 직접 선택하고 있다.
    • MemberRepository memberRepository = new MemoryMemberRepository(); // 기존 코드
    • MemberRepository memberRepository = new JdbcMemberRepository(); // 변경 코드
  • 구현 객체를 변경하려면 클라이언트 코드를 변경해야 한다.
  • 분명 다형성을 사용했지만 OCP 원칙을 지킬 수 없다.
  • 해결 : 객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자가 필요하다. -> DI, IoC

(3) 리스코프 치환 원칙 (LSP : Liskov Substitution Principle)

  • 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
  • 다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다는 것, 다형성을 지원하기 위한 원칙, 인터페이스를 구현한 구현체는 믿고 사용하려면, 이 원칙이 필요하다.
  • 단순히 컴파일에 성공하는 것을 넘어서는 이야기
  • 예) 자동차 인터페이스의 엑셀은 앞으로 가라는 기능, 뒤로 가게 구현하면 LSP 위반, 느리게 가더라도 앞으로 가야함

(4) 인터페이스 분리 원칙 (ISP : Interface Segregation Principle)

  • 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
  • 자동차 인터페이스 -> 운전 인터페이스, 정비 인터페이스로 분리
  • 사용자 클라이언트 -> 운전자 클라이언트, 정비사 클라이언트로 분리
  • 분리하면 정비 인터페이스 자체가 변해도 운전자 클라이언트에 영향을 주지 않음
  • 인터페이스가 명확해지고, 대체 가능성이 높아진다.

(5) 의존관계 역전 원칙 (DIP : Dependency Inversion Principle) (의존하다: 알고있다, 바라본다)

  • 프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다. 의존성 주입은 이 원칙을 따르는 방법 중 하나다.
  • 쉽게 이야기해서 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻
  • 앞에서 이야기한 역할(Role)에 의존하게 해야 한다는 것과 같다. 객체 세상도 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있다! 구현체에 의존하게 되면 변경이 아주 어려워진다.
  • OCP에서 설명한 MemberService는 인터페이스에 의존하지만, 구현 클래스도 동시에 의존한다.
  • MemberService 클라이언트가 구현 클래스를 직접 선택
    • MemberRepository memberRepository = new MemoryMemberRepository();
  • DIP 위반

[ 정리 ]

  • 객체 지향의 핵심은 다형성
  • 하지만 다형성 만으로는 쉽게 부품을 갈아 끼우듯이 개발할 수 없다.
  • 다형성 만으로는 구현 객체를 변경할 때 클라이언트 코드도 함께 변경된다.
  • 다형성 만으로는 OCP, DIP를 지킬 수 없다.
    • 스프링은 다음 기술로 다형성 + OCP, DIP를 가능하게 지원
      • DI(Dependency Injection): 의존관계, 의존성 주입
      • DI 컨테이너 제공
      • 결과 : 클라이언트 코드의 변경 없이 기능 확장 -> 쉽게 부품을 교체하듯이 개발
  • 모든 설계에 역할구현을 분리하자.
  • 애플리케이션 설계도 공연을 설계 하듯이 배역만 만들어두고, 배우는 언제든지 유연하게 변경할 수 있도록 만드는 것이 좋은 객체 지향 설계다.
  • '이상적으로는' 모든 설계에 인터페이스를 부여하자.
    • [ 실무고민 ]
    • 하지만 인터페이스를 도입하면 추상화라는 비용이 발생한다.
    • 기능을 확장할 가능성이 없다면 구체 클래스를 직접 사용하고, 향후 꼭 필요할 때 리팩터링해서 인터페이스를 도입하는 것도 방법이다.

참조

'프로그래밍 > 스프링 자바' 카테고리의 다른 글

[Java] JVM, 자바 메모리, GC  (0) 2021.07.03
[Spring] 스프링 개념 정리  (0) 2021.06.30
JUnit5 정리  (0) 2021.06.28
TDD , 단위 테스트, 리팩토링  (0) 2021.06.28
[Spring] Spring MVC 이동 구조 (feat. jsp)  (0) 2021.04.20