
객체지향
객체지향 프로그래밍이란 ?
프로그래밍에서 필요한 데이터를 추상화 시켜 상태화 행위를 가진 객체로 만들고, 객체들간의 상호작용을 통해 로직을 구성하는 프로그래밍 방법
객체지향 프로그래밍의 장단점
장점
- 상속 캡슐화 다형성의 특징으로 코드를 재사용하거나 확장하기 좋아서 유지보수가 쉽다.
- 관련이 많은 객체의 상호작용을 생각해 실세계에 대한 모델링을 조금 더 쉽게 해준다.
- 캡슐화 특징으로 실제로 구현되는 부분을 외부에 드러나지 않도록 은닉하여 보안성이 높다.
단점
- 캡슐화와 격리구조 때문에 절차지향 프로그래밍보다 실행 속도가 느리다.
- 객체 단위의 구성으로 필요한 절차지향 프로그래밍보다 메모리 비용이 크다.
OOP(객체지향 프로그래밍, Object-Oriented Programming) 의 4가지 특징
-
캡슐화
객체가 역할을 수행하기 위한 정보와 기능을 하나로 묶어서 데이터를 외부로부터 보호하는 것
- 클라이언트에게는 인터페이스만 제공을 해서 필요한 정보만 노출하고, 실제 구현 정보는 숨겨서 기능만 사용할 수 있게 한다.
- 필드는 private으로 접근을 막고, 메서드를 public으로 열어서 캡슐화를 사용한다.
-
추상화
객체지향에서 모델링 방법을 얘기한다. 실제 현실 객체에서 필요 없는 부분은 빼고, 필요한 부분만을 추출하여 사용한다.
즉, 객체의 공통적인 속성과 기능을 추출하여 정의하는 것을 의미한다.
- 추상 클래스와 인터페이스로 추상화를 구현할 수 있다.
- 어떤 객체의 행위를 추상 클래스 또는 인터페이스로 규정해 두고, 실제 구현은 구현체에서 하도록 프로그래밍을 설계할 수 있다.
-
상속
상위 클래스의 특성을 하위 클래스가 물려받는 것을 말한다.
상속을 받은 자식 클래스는 부모 클래스와 계층적 관계를 갖게 된다.
상위 클래스에서 하위 클래스로 내려갈수록 구체화되는 것이 중요하다.
- 부모 클래스의 메서드 또는 필드를 자식 클래스에서 접근하여 사용할 수 있다.
-
다형성
하나의 메서드를 여러 가지 형태로 변화시킬 수 있는 것을 말한다.
overriding 과 overloading을 통해 구현한다.
- overrding : 부모 클래스의 메서드를 자식 클래스에서 재정의하는 것 (반환값, 매개변수) 는 유지하되, 내부 구현을 재정의
- overloading : 같은 이름의 메서드를 매개변수의 타입 또는 개수를 다르게 하여 여러 개 정의하는 것
- 생성자 오버로딩이 있다.
객체 지향 설계 5원칙
SRP (Single Responsibility Principal) : 단일 책임 원칙
하나의 클래스는 하나의 기능만을 가져야 하고, 하나의 클래스를 변경해야 하는 이유는 하나뿐이어야 한다는 원칙
단일 책임 원칙을 지키면 객체 간의 결합이 느슨해지고, 잘 지키지 못하면 여러 클래스가 복잡하게 결합되어 변경이 일어날 때 고쳐야 하는 부분이 많아지게 됩니다.
- 변경에 의한 연쇄 작용 감소
- 가독성, 유지보수성 향상
OCP (Open Closed Principal) : 개방 폐쇄 원칙
확장에는 열려있고, 변경에는 닫혀 있어야 한다는 원칙
요구사항이 추가되어 기능을 확장할 때, 기존 구성 요소는 수정하지 않고 쉽게 기능을 추가할 수 있도록 설계해야 한다.
- 객체지향의 추상화와 다형성을 활용하면 개방폐쇄 원칙을 잘 지킬 수 있다.
LSP (Liskov Substitution Principal) : 리스코프 치환 원칙
서브 클래스를 항상 상위 클래스로 교체할 수 있어야 한다는 원칙
자식 클래스는 항상 부모 클래스에서 가능한 행위를 항상 수행할 수 있어야 한다는 의미
- 인터페이스의 구현체가 여러 개 있을 때, 구현체를 갈아 끼워도 구현체를 사용하는 곳에서는 똑같이 동작
- 클래스나 인터페이스의 상속을 이용해 확장성을 얻을 수 있고, 이 때문에 인터페이스를 만들어 사용하는 게 좋다.
ISP (Interface Segregation Principal) : 인터페이스 분리 원칙
사용하지 않는 메서드를 가진 인터페이스는 필요한 기능만을 담은 인터페이스로 분리해서 사용하라는 원칙
클라이언트에게 꼭 필요한 기능만을 가진 인터페이스를 제공해야 합니다.
- 특정 인터페이스가 1,2,3,4의 기능이 있는데, 클라이언트 A는 1,2의 기능을 사용하고, 클라이언트 B는 2,3,4의 기능을 사용한다면 A에게는 1,2의 기능만을 담은 인터페이스를 제공하고, B에게는 2,3,4의 기능만을 담은 인터페이스를 만들어서 제공하는 게 좋다.
DIP(Dependency Inversion Principal) : 의존 역전 원칙
하위 모듈이 변경될 때, 상위 모듈은 변경되지 않도록 설계해야 한다는 원칙
추상화(인터페이스)에 의존해야하고, 구체화(클래스)에 의존하면 안된다.
- Spring 에서는 DI를 이용하여 DIP를 잘 지키도록 한다.
- 상위 모듈인 Controller에서 하위 모듈인 Service 인터페이스를 의존할 때, 하위 모듈인 Service의 구현체를 변경해도 상위 모듈인 Controller는 변경되지 않도록 한다.
- DI : Dependency Injection으로 의존성 주입
- DIP : 의존성 역전 원칙
- Controller에서는 @Bean으로 등록된 Service 구현체를 주입받아서 사용한다.
클래스 vs 객체 vs 인스턴스의 차이
클래스 : 객체를 만들기 위한 코드, 틀, 명세 같은 느낌
객체 : 클래스에서 선언된 모양 그대로 생성하면 객체
인스턴스 : 객체가 생성되어 메모리에 할당되면 그것이 인스턴스
인터페이스와 추상 클래스의 차이
공통점
- new 연산자로 인스턴스를 생성할 수 없다.
- 사용하기 위해서는 하위 클래스에서 확장/구현해야 한다.
인터페이스
- 구현체들이 같은 동작을 한다는 걸 보장하기 위해 사용한다. → 하위 클래스가 반드시 모든 메서드를 구현해야 한다.
- 다중 상속이 가능하고, 구현체들 간에 연관관계가 없을 수 있다.
- 구현 내용 변경이 용이하게 하도록 하기 위해 인터페이스를 사용한다.
추상 클래스 (abstract class)
- 객체들의 공통된 개념을 묶어서 추상화시키고, 기능 확장을 위해 사용한다.
- 추상 클래스를 상속받는 객체들 간에는 연관관계가 있다.
좋은 객체 지향 프로그래밍이란 ?
“역할과 구현을 분리”
인터페이스를 안정적으로 잘 설계하는 것이 중요하다.
- 실세계의 역할과 구현 이라는 편리한 컨셉을 다형성을 통해 객체 세성으로 가져올 수 있음
- 유연하고, 변경이 용이
- 확장 가능한 설계
- 클라이언트에게 영향을 주지 않는 변경 가능