OOP
- Opject-Oriented Programming 의 약자로서 객체 지향적인 프로그래밍이란 뜻이며, C언와 같이 절차 지향적인 프로그래밍이 아닌 객체의 관점에서 프로그래밍을 한다는 것을 의미한다.
- OOP는 객체를 기준으로 코드를 나누어 구현한다. 자바의 경우 그 구성 부분 단위가 클래스이다. 풀어설명하자면 클래스는 설계도고 직접일을 하는 구현체는 인스턴스이다.(객체와 인스턴스는 엄격히 보자면 다른 의미이므로 인스턴스로 표현한다)
- OOP는 절차지향에 비해서 사람의 사고방식과 더 가깝다고 한다.
- OOP는 객체들의 유기적인 관계를 통해서 프로세스가 진행된다.
- 애플리케이션을 구성하는 요소들을 객체로 바라보고, 객체들을 유기적으로 연결하여 프로그래밍 하는 것을 말한다.
- 자바 프로그래밍이라고 하면 객체지향프로그래밍 OOP라고 해도 무방하다.
특징
캡슐화(Encapsulation)
- 캡슐화란 하나의 객체에 대해 그 객체가 특정한 목적을 달성하기 위해 필요한 변수나 메소드를 하나로 묶는 것을 의미한다.
- 따라서 클래스를 우리가 만들 때 훗날 이 클래스에서 만들어진 객체가 특정한 목적을 잘 수행할 수 있도록 사용해야할 변수와 그 변수를 가지고 특정한 액션 즉 메소드를 관련성 있게 클래스에 구성해야한다.
정보은닉
- 캡슐화를 하는 목적은 바로 정보은닉이다. 유저 정보를 가지고 있는 User라는 객체에서 유저의 정보가 public으로 선언되어 있다면, 누구든 접근해서 유저 정보를 변경할 수 있다. 따라서 private으로 데이터를 보호해서 접근을 제한해야한다.
- 이렇게 보호된 변수는 getter나 setter등의 메소드를 통해서만 간접적으로 접근이 가능하도록 하는 것이 캡슐화의 중요한 목적이다.
추상화(Abstration)
- 추상화는 목적과 관련이 없는 부분을 제거하여 필요한 부분만을 표현하기 위한 개념이다.
- 세상에 있는 것을 본따 클래스ㅁ를 만들고 그 클래스의 상태와 행동을 부여한 객체를 만든다.
- 그러나 세상에 모든 것을 다 클래스에 담고 객체를 만드는 것은 불가능하다. 그래서 추상적으로 생각해 일단 큰틀의 클래스를 구현하고 거기에 최소 이러한 공통적인 요소나 필수 적인 요소는 들어갔으면 하는 바램에서 만든 것이 추상 클래이다.
- 이과정에서 공통적인 요소나 특징을 추출하는 과정이 추상화이다.
- 예를 들어 벤츠, 아우디, 티코 등등 우리가 생각하는 여러 종류의 자동차가 있다. 이것을 더 클래스화하고 변수와 메서드 등을 개별적으로 만드는 것은 무모한 것이다.(즉, 확장성 때문에 추상화할 필요가 있다.) 따라서 위에 나열한 자동차들의 공통적인 요소나 특징을 추철하는 과정인 추상화를 거쳐 요소를 끄집어내면 바퀴, 핸들, 차문, 유리창 등 필수적인 부품이 있다. 바퀴는 굴러가고, 핸들은 돌아가고 차문은 열려야 한다. 등등 공통적인 행동 즉 어떤 자동차든 필수적으로 필요한 행위를 표현한 메소드가 추출된다.
- 위의 설명된 예시의 과정이 추상화 과정이라고 볼 수 있다. 추상적으로 끄집어 낸 개념들을 큰 틀에서 클래스로 만든것이 바로 추상클래스이다.
- 다시 정리해서 이를 객체와 클래스의 관점에서 보면 객체들은 실제 그 모습이지만, 클래스는 객체들이 어떤 특징들이 있어야 한다고 정의하는 추상화된 개념이다.
- 최종적으로 추상화는 객체들의 공통된 특징을 파악해 정의해 놓은 설계 기법이라고 할 수 있다.
다형성(Polymorphism)
- 다형성은 상속을 통해 기능을 확정하거나 변경하는 것을 가능하게 해준다. 즉, 다형성은 형태가 같은데 다른 기능을 하는 것을 의미한다.(같은 동작이지만 결과가 다른경우 다형이라고 생각하면 된다.)
- 예를 들어 고양이 클래스에는 울음이라는 속성이 정의되어 있다고 하면, 사자는 고양이 과이므로 사자 클래스는 고양이 클래스를 상속 받고, 사자 클래스에도 "울음"이라는 속성이 자동으로 추가된다. 이것을 상속이라고 한다.
- 하지만 고양이와 사자의 울음소리는 다르다. 같은 "울음" 속성임에도 실제 울음소리는 다르다. 같은 고양이과의 "울음"속성을 가지고 있지만 소리는 다르다. 이런것을 다형성이라고 표현할 수 있다.
- OOP에서 다형성의 개념을 녹여내는 방법은 두가지가 있는데 오버라이딩(Overriding)과 오버로딩(Overloading)이다.
- 오버라이딩
- 부모 클래스에서 상속받은 자식 클래스에서 부모클래스에서 만들어진 메소드를 자식 클래스에서 자신의 입맛대로 다시 재정의해서 사용하는 것을 말한다.
- 오버로딩
- 같은 이름의 메소드를 사용하지만 메소드마다 다른 용도로 사용되며 그 결과물도 다르게 구현할 수 있게 만드는 개념
- 오버로딩이 가능하려면 메소드끼리 이름은 같지만 매개변수의 갯수나 데이터 타입이 다르면 오버로딩이 적용된다.
- 메소드 이름이 같아도 문법에러가 나지 않는다.
상속성, 재사용(Inheritance)
- 상속은 객체지향의 꽃이라고 표현할 수 있다.
- 상속이란 기존 상위클래스에 근거하여 새롭게 클래스와 행위를 정의할 수 있게 도와주는 개념이다.
- 기존 클래스에 기능을 가져와 재사용할 수 있으면서도 동시에 새롭게 만든 클래스에 새로운 기능을 추가할 수 있게 만들어준다.
상속의 개념
- 실제 세계에서 부모로부터 여러가지를 상속을 받는데, OOP에서도 부모 클래스와 자식클래스라고 표현하며 자식클래스는 부모클래스의 속성을 물려받을 수 있다.
- 예를 들어, 고양이와 강아지라는 클래스가 존재한다고 가정해보자. 이 둘은 모두 포유류에 해당된다. 포유류는 여러 속성들이 정의되어 있는데 고양이와 강아지는 포유류의 가지는 속성들을 그대로 갖고 있다.
- 하지만 공통된 속성을 가지고 있음과 동시에 서로 너무나 많이 다른 특성들을 가지고 있다. 그로 인해 디테일하게 고양이, 강이지로 나눈것이다.
- 포유류라는 클래스는 고양이와 강아지 클래스에게 속성들을 물려준다. 이것을 상속이라고 하고, 고양이과 강아지클래스는 포유류 클래스와 상속관계라고 표현한다.
상속이 필요한 이유??
- 상속이 필요한 이유는 코드의 중복을 없애기 위함이다.
- 코드의 중복이 많아지면 개발 단계에서도 피곤하지만, 유지 보수단계에서 많은 비용이 들게 된다.
- 그래서 개발을 할때 코드의 중복은 반드시 피해야 한다.
- OOP에서는 상속을 통해 코드의 중복 문제를 일부 해결할 수 있다.
- 포유류 클래스에 여러 속성들을 정의해 놓고 포유류에 해당하는 동물, 예를들어 강아지 클래스가 필요하는 경우 포유류 클래스와 상속 관계를 맺는다.
- 상속 관계를 맺으면 자식 객체를 생성할 때 부모 클래스의 속성들을 자동으로 물려받기 떄문에 자식 클래스에서 또 정의 할 필요가 없다.
- 이것이 상속이 필요한 이유이다.
객체지향 5대원칙(SOLID)
SRP (단일 책임 원칙)
- 한 클래스는 하나의 책임만 가져야한다.
- 하나의 책임이라는 것은 모호하다.
- 책임은 클 수 있고, 작을 수도 있다.
- 문맥과 상황에 따라 다르다.
- 중요한 기준은 변경이다.
- 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것이다.
OCP (개방 - 폐쇄 원칙)
- 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
LSP (리스코프 치환 원칙)
- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
- 다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다.
- 자동차 인터페이스를 예시로 들자면, 엑셀이라는 메소드는 앞으로 가라는 기능이다. 이 인터페이스를 구현한 클래스에서 해당 메소드를 뒤로가게 구현했다면 이는 LSP를 위반한 것이다. 느리더라도 앞으로 가야한다.
ISP (인터페이스 분리 원칙)
- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
- 자동차 인터페이스 -> 운전 인터페이스, 정비 인터페이스
- 사용자 클라이언트 -> 운전자 클라이언트, 정비사 클라이언트
- 인터페이스가 명확해지고, 대체 가능성이 높아진다.
DIP (의존관계 역전 원칙)
- 프로그래머는 "추상화에 의존해야지, 구체화에 의존하면 안된다." 의존성 주입은 이 원칙을 따라는 방법 중 하나다.
- 구현 클래스에 의존하지 말고, 인터페이스에 의존해야 한다.
- 구현체에 의존하게 되면 변경이 어렵다.
- 예) 연극에서 남자 배우는 상대 배우 역할에 의존을 해야한다. 그래야 상대 배우가 바뀌더라도 큰 영향을 받지 않을 수 있다. 상대 배우에게 의존하게 된다면 상대 배우가 바뀌었을 때 큰 영향을 받게 된다. 이는 DIP를 위반한 예시라고 볼 수 있다.