객체 지향 프로그래밍

송은혜·2022년 6월 4일
0

JAVA

목록 보기
3/8

객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러개의 독립된 단위, 즉 "객체"들의 모임으로 파악하고자 하는 것이고, 그 객체들을 기반으로 하는 프로그래밍 방식이다. 각각의 객체는 메시지를 주고받고 데이터를 처리할 수 있고, 그 객체들을 서로서로 협력 관계로써 사용하고 프로그래밍하는 것이라고 말할 수 있겠다.

예를 들어, 자동차 공장에 대해 프로그래밍을 한다면

크게 , 공장이라는 것이 있을 것이고 자동차도 여러가지 차종이 있을테니 이 공장에서 생산하는 여러 차종이 있을 것이다. 또, 자동차에는 여러 부품들도 있을 것이다.

공장이나 자동차와 같은 어떤 사물이나 대상은 물론이고, 방식 같은 것들을 하나의 대상으로 여기고 프로그래밍을 하는 것이다.

간단히 생각해본다면,

공장 class / 제네시스 class / 쏘나타 class / 그랜저 class 등이 있을 것이고

재료 class 안에는 재료 A / 재료 B 등을 넣어주고,

만들어내는 방식에 대한 class 에는 방식 A / 방식 B / 방식 C 등을 넣어줄 수 있을 것이다.

만약 제네시스에는 재료 A 와 방식 A를 사용한다면, 재료 class에 있는 재료 A와 방식 class에 있는 방식A 를 사용해주면되고 ,

쏘나타에는 또 쏘나타가 사용하는 재료와 방식을 각각 class에서 꺼내 사용할 수 있을 것이다.

또, 공장 class에는 각 차종들의 공통되는 부분들을 넣어줄 수 있을 것이다.

이런 식으로 프로그래밍을 하게되면, 각각 차종들에게 필요한 것들을 각각의 차종마다 a부터 z까지 전부 입력해주지 않을 수 있다.

규모가 큰 프로젝트일 수록 객체지향 방식을 사용하면 조금 더 쉽게 관리할 수 있을 것이다.


객체 지향에는 몇가지 특징들과 규칙이 존재하고 , 좋은 객체 지향 프로그래밍을 한다는 것은 해당 특징과 규칙들을 지키며 하는 프로그래밍이라고 할 수 있겠다.



객체 지향의 특징

  1. 추상화

    정리해놓은 페이지를 읽어보자 추상화

    추상화는 여러객체에 공통적으로 사용되는 속성들을 뽑아내는 것을 말한다.
    그 속성들을 뭉쳐 추상클래스로 만든뒤, 상속을 통해 각 객체가 객체의 스타일에 맞게 구현하도록한다.


  2. 캡슐화

    캡슐화(영어: encapsulation)는 객체 지향 프로그래밍에서 다음 2가지 측면이 있다

    • 객체의 속성(data fields)과 행위(메서드, methods)를 하나로 묶고,
    • 실제 구현 내용 일부를 내부에 감추어 은닉한다.

    -위키피디아

    관련이 있는 변수와 함수를 하나의 클래스로 묶고 외부에서 쉽게 접근하지 못하도록 은닉하는것이 캡슐화의 핵심이다. 객체에 직접적인 접근을 막고 외부에서 내부의 정보에 직접접근하거나 변경할 수 없고, 객체가 제공하는 필드와 메소드를 통해서만 접근이 가능하다.

    (연관되는 정보를 묶고 외부에서 쉽게 접근하지 못하도록 하는 행위가 마치 캡슐안에 담는 것같아서 캡슐화라고 하는 것 같다.)

    • 정보은닉(Information Hiding)의 장점.

      (외부에서 객체접근하는데 있어서 정보를 숨기고 객체의 연산을 통해서만 접근이 가능하게 하는 것.)

      정보은닉의 장점은 외부에서 특정 객체의 데이터 및 함수를 직접 접근을 막음으로써 변경을 못하게 하고 유지보수나 확장시 오류의 범위를 최소화 할 수 있고, 객체내 정보손상, 오용을 방지하고, 조작법이 바뀌어도 사용방법 자체는 바뀌지 않고, 데이터가 변경되어도 다른 객체에 영향을 주지 않기 때문에 독립성이 좋고, 처리된 결과사용으로 이식성이 좋고객체를 모듈화 할 수있어 새로운 시스템의 구성에 하나의 모듈처럼 사용이 가능하다.

      접근제어자와 getter , setter 를 이용해, 정보은닉의 기능을 적절히 수행할 수 있다.


  1. 상속

    상속(inheritance)이란 ? (정리해둔 페이지를 읽어보자) 상속관계

    우리는 상속이라는 말을 들으면 어떠한것을 물려받는 것 이라는 생각을 한다. 객체지향에서 말하는 상속에 의미도 이와 동일하다고 볼 수 있다.

    클래스들 사이에서 상속이 일어나는데, 일반적으로 무언가를 물려”주는” 클래스를 상위클래스,수퍼클래스 혹은 부모클래스라고 일컫으며, 상속을 “받는” 클래스를 하위클래스, 서브클래스 혹은 자식클래스 라고 한다.

    상속이란 보통 부모와 자식간에 일어나는 일이므로 편하게 부모 클래스와 자식클래스로 지칭해보겠다.

    객체지향에서 상속이란, 부모클래스의 속성을 자식클래스가 “상속을 받는다” 라는 의미.

    extends 를 사용하여 상속을 받는다.

    class Cildren extends Parents (){
    ...
    }

    상속받은 속성을 모두 사용할 수 있으며, 재정의(override)할 수도 있고, 자식클래스만의 속성을 추가로 부여할 수도 있다. ⇒ 자식 = 부모속성 +@

    이러한 부분때문에 자식클래스로 인스턴스를 생성할 때 이 클래스의 자료형을 부모클래스로 형변환할 수 있지만, (=업캐스팅(upcating)이라고한다.) 반대로 부모클래스로 인스턴스를 생성할 때 자식클래스로 형변환은 불가능하다. → 자식은 부모의 모든걸 담고 있지만 , 부모는 자식이 +@시킨 성질을 가지지 못하기때문.

    Parents p = new Cildren(); => 묵시적 형변환 가능. 업캐스팅.
    Cildren c = new Parents(); => 불가능.
    (자료형) 변수명 = 인스턴스생성자;

  1. 다형성

    다형성?

    프로그램 언어의 다형성
    (多形性, polymorphism; 폴리모피즘)은 그 프로그래밍 언어의 자료형 체계의 성질을 나타내는 것으로, 프로그램 언어의 각 요소들(상수변수오브젝트함수메소드 등)이 다양한 자료형(type)에 속하는 것이 허가되는 성질을 가리킨다. 반댓말은 단형성
    (monomorphism)으로, 프로그램 언어의 각 요소가 한가지 형태만 가지는 성질을 가리킨다.
    - 위키피디아

    위키피디아에 명시되어 있는 다형성에 대한 의의가 잘 와닿아서 가져와보았다.




객체 지향 5 규칙 (SOLID설계 원칙)

로버트 마틴이 설계한 올바른 객체지향에 대한 설계원칙으로 , 프로그래머가 시간이 지나도 유지 보수와 확장이 쉬운 스스템을 만들고자 할 때, 이 원칙들을 적용하도록 권한다.

솔리드 원칙들은 소프트웨어 작업에서 프로그래머가 소스 코드가 읽기 쉽고 확장하기 쉽게 될 때까지 소프트웨어 소스 코드를 리팩터링하여 코드 냄새를 지우도록 한다. (코드냄새→ 문제를 일으킬 가능성이 있는 소스코드를 가리킨다.)

솔리드 원칙을 지키기위해 IoC, DI, 컨테이너가 만들어졌다고 볼 수 있기때문에 이해가 잘 안된다면 IoC,DI,컨테이너를 먼저 찾아보고 솔리드 원칙을 읽어보면 좀 더 이해가 잘 될 것이다.


  • S 단일 책임 원칙 SRR(Sing Responsibility Rrinciple) 객체 지향 프로그래밍에서 단일 책임 원칙(single responsibility principle)이란 모든 클래스는 하나의 책임만 가지며, 클래스는 그 책임을 완전히 캡슐화해야 함을 일컫는다. 클래스가 제공하는 모든 기능은 이 책임과 주의 깊게 부합해야 한다.
    -위키피디아
    객체지향에서는 각각의 객체들에게 일정한 역할을 부여해준다. 예를 들어, 배달앱을 이용하면서 , A음식점에서 메뉴를 골라 장바구니에 담고, 주문을 하는 과정을 생각해보자. 이 경우 크게는 음식점 , 메뉴 , 장바구니를 객체로 생각할 수 있을 것이다. 하지만 더 세분화를 해보면 음식점, 메뉴, “장바구니에 담기는 메뉴목록” , 장바구니 이렇게 4가지로 분리를 할 수도 있다. 메뉴를 선택해서 장바구니에 담는것이라 쉽게 생각했을때는 메뉴를 장바구니에 넣는건데 “장바구니에 담기는 메뉴 목록”은 왜 필요하지 ? 라는 의문이 들 수 있을 것이다. 하지만, 단일 책임 원칙을 생각해본다면 메뉴는 그저 음식점에 등록되는 메뉴일 뿐인 것이다.
    메뉴는 음식점에 담겨서 해당 음식에 대한 정보를 보여주는 역할을 하는 것이고 , 장바구니로 담기는 것은 또 다른 역할이 된다. 단일 책임 원칙에서 중요한 기준은 변경이다. 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것이라고 볼 수 있다. -인프런 김영한님

  • O 개방 폐쇄 원칙 OCP(Open=Closed Principle)

    개방-폐쇄 원칙(OCP, Open-Closed Principle)은 '소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다'는 프로그래밍 원칙이

    -위키피디아

    위에 나와 있듯이 , 개방-폐쇄 원칙에는 두 가지 속성이 있다.
    1. 확장에 대해 열려 있어야함.

    2. 수정에 대해 닫혀 있어야함.

      처음에 이 속성을 들었을 때는 상당히 의아했다. 확장에 대해 열려 있어야하는건 당연하다고 생각이 들었지만, 수정에 대해 닫혀있어야한다?.. 수정을 하려고 하는데.. 닫혀있으면 어떻게 수정을 하지??..

      의아했던 부분이 인프런에서 김영한님의 강의도 듣고, 위키피디아에 나와 있는 추가적인 설명으로 이해할 수가 있었다.

      김영한님께서는 아주 직관적으로, 클라이언트 코드는 변경이 되면 안된다고 하셨다.

      그 말을 듣고 위키피디아의 설명을 읽어보니 단박에 이해가 되었다.

      모듈은 고정된 추상화에 의존하기 때문에 수정에 대해 닫혀 있을 수 있고, 반대로 추상화
      의 새 파생 클래스를 만드는 것을 통해 확장도 가능하다. 따라서 추상화는 개방-폐쇄 원칙의 핵심 요소이다.
      ...
      이 원칙을 무시하고 프로그래밍을 한다면, 객체 지향 프로그래밍의 가장 큰 장점인 유연성, 재사용성, 유지보수성 등을 결코 얻을 수 없다. 따라서 객체 지향 프로그래밍 언어에서 개방-폐쇄 원칙은 반드시 지켜야할 기본적인 원칙이다.

      -위키피디아 중 ..

      어떤 정보를 받아서 최종적으로 외부에 정보를 건내주는 객체(클라이언트 코드)가 수정에 대해닫혀있어야한다는 말이고, 이 객체에 정보를 주는 클래스 혹은 인터페이스들의 코드만 수정을 하는 것이다.

      이 원칙을 지키기위해 자바에서는 스프링을 이용하기도 한다. 스프링에있는 DI컨테이너를 사용하면 클라이언트 코드는 변경되는 것 없이 참조되는 클래스의 정보만 변경을 해주면 클라이언트 코드에도 변경된 정보가 잘 주입된다.

      이 부분에 대해서는 DI를 정리해둔 걸 참고하면 좋을 것 같다. IoC,DI,컨테이너

      객체지향 프로그래밍 중 큰 특징이 유지보수가 쉽고 유연하다는 것인데 이 말을 쉽게 풀면, 다 구성해놓은 코드에 일정부분을 수정해야 할 일이 생겼을때 , 해당 부분이 참조되어 있는 모든 코드를 수정할 필요없이 일부만 수정을 해주면 나머지도 잘 작동을 한다는 것이다.

      이러한 이점은 객체지향의 특징과 규칙들을 잘 준수하여 올바른 객체지향 코드를 작성했을 경우 우리가 얻을 수 있는 부분이고, 그 중 개방-폐쇄 원칙을 준수하지 않는다면 얻기 힘든 이점이고 우리는 상속을 통해서 다형성을 만들어줄 수 있고, 다형성 + 추상화를 통해 개방-폐쇄 원칙을 지킬 수 있다.


  • L 리스코프 치환 원칙 LSP(Liskov substitution principle)

    리스코프 치환 원칙은 "상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다."를 의미합니다.
    단순히 컴파일에 성공하는 것을 넘어서, 특정 메서드에 구현하고자 했던 기능의 의도가 변질 되어서는 안된다는 것이다.

    → 상속을 받고 있는 하위의 객체가 상위의 객체의 메소드를 상위에서 의도한 것과 맞지 않게 오버라이딩을 하게 되면, 원래 의도하고자 했던 의도가 변질될 수 있다.

    => 의도가 변질 되면, 하위 객체로 치환하게 되면 당연히 의도했던 대로 이루어지지 않을 것이다.

    리스코프 치환 원칙을 지키지 않으면, 개발 폐쇄 원칙을 위반하게 된다.
    → 기능 확장을 위해 더 많은 부분을 수정해야함.


  • I 인터페이스 분리 원칙 ISP(Interface segregation principle)

    인터페이스 분리 원칙은 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 원칙이다.[1]
    인터페이스 분리 원칙은 큰 덩어리의 인터페이스들을 구체적이고 작은 단위들로 분리시킴으로써 클라이언트들이 꼭 필요한 메서드들만 이용할 수 있게 한다. 이와 같은 작은 단위들을 역할 인터페이스라고도 부른다.[2]
    인터페이스 분리 원칙을 통해 시스템의 내부 의존성을 약화시켜 리팩토링, 수정, 재배포를 쉽게 할 수 있다. 인터페이스 분리 원칙은 SOLID 5원칙의 하나이며, GRASP의 밀착 원칙과 비슷하다.
    -위키피디아

    하나의 인터페이스에 이 기능 저 기능 메서드를 다 넣지 말고, 세분화시켜 인터페이스를 쪼개어 만들어주고 , 단일 책임 원칙에 의해 역할을 하나씩 할당받은 객체들에게 본인들이 해야할 일들에 해당하는 인터페이스만을 참조시켜준다.

    인터페이스를 세분화해서 여러개로 만들어주므로, 코드를 명확하고 직관적으로 읽어볼 수 있고, 특정 부분에 변경사항이 생겼을 때 해당 역할을 수행하는 인터페이스 부분만 변경을 해주면 되서 보다 유연한 수정, 유지보수를 할 수 있게 된다.


  • D 의존관계 역전 원칙 DIP(Dependency inversion principle)

    프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안된다.” 의존성 주입은 이 원칙
    을 따르는 방법 중 하나다. 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻이다. - 인프런 김영한님

    ex) 큰 틀이 되는 상위 인터페이스를 구현하고, 해당 인터페이스를 구현하는 하위 클래스들을 여러개 만들었다. 그리고 클라이언트객체가 하위 인터페이스를 직접 참조한다. ⇒ 이것은 구체화에 의존하는 것. DIP를 어기는 것이다. 클라이언트객체는 구체적으로 본인에게 어떤 정보가 들어올지 몰라야한다. ⇒ 추상화에 의존해야한다. 다르게 표현한다면, 자신보다 변하기 쉬운 것에 의존하지 않는 것이라고 할 수 있겠다.

0개의 댓글