프로그래밍 패러다임
프로그래밍 패러다임은 프로그래머에게 프로그래밍의 관점을 갖게 해주는 역할을 하는 개발 방법론
1.2.2 객체지향 프로그래밍
객체지향 프로그래밍은 객체들의 집합으로 프로그램의 상호 작용을 표현하며 데이터를 객체로 취급하여 객체 내부에 선언된 메서드를 활용하는 방식
객체 : 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별 가능한 것을 말한다.
객체는 속성과 동작으로 구성되어 있고 자바는 이 속성과 동작들을 각각 필드(field)와 메소드(method)로 구분
객체지향 프로그래밍 특징 4가지
- 추상화
- 비슷한 역할을 하는 attribute나 method를 묶어서 하나의 모델로 만들어 내는 것 ex) 자동차, 오토바이 → 탈것 역할과 구현의 분리
public interface Vehicle { public abstract void start(); // 추상메소드 void moveForward(); // public abstract 키워드 생략 가능 void moveBackward(); }
public class Car implements Vehicle { @Override public void moveForward(){ System.out.println("자동차 전진"); } @Override public void moveBackward(){ System.out.println("자동차 후진"); } }
public class MotorBike implements Vehicle { @Override public void moveForward(){ System.out.println("오토바이 전진"); } @Override public void moveBackward(){ System.out.println("오토바이 후진"); } }
- 캡슐화
- 객체의 속성과 메서드를 하나로 묶고 일부를 외부에 감추어 은닉하는 것을 말한다.
ex) 자바의 접근제어자
- Public : 접근 제한이 전혀 없다
- Protected : 상속클래스 및 같은 패키지에서만 사용 가능
- Default : 같은 패키지 내에서 사용 가능
- Private : 정의된 클래스 내부에서만 사용 가능. Getter,Setter를 이용해 정보 접근 or 수정
- 객체의 속성과 메서드를 하나로 묶고 일부를 외부에 감추어 은닉하는 것을 말한다.
ex) 자바의 접근제어자
- 상속
- 상위 클래스의 특성을 하위 클래스가 이어받아서 재사용하거나 추가, 확장하는 것을 말합니다. 코드의 재사용 측면, 계층적인 관계 생성, 유지 보수성 측면에서 중요합니다.
public class Person { public void walk() { System.out.println("걷는다"); } public void talk() { System.out.println("말한다"); } } public class Chef extends Person { }
- 다형성
- 하나의 메서드나 클래스가 다양한 방법으로 동작하는 것을 말합니다. 대표적으로 오버로딩, 오버라이딩, 그리고 상속받은 객체의 참조변수 형변환이 있습니다.
오버로딩과 오버라이딩
- 오버로딩
- 같은 이름을 가진 메서드를 여러 개 두는 것. 메서드의 타입, 매개변수의 유형, 개수 등으로 여러개를 둘 수 있으며 컴파일 중에 발생하는 ‘정적’ 다형성이다.
- 오버라이딩
- 상위 클래스로부터 상속받은 메서드를 하위 클래스가 재정의하는 것을 의미하며 런타임 중에 발생하는 ‘동적’ 다형성이다.
상속받은 객체의 참조변수 형변환
상속받은 객체에 대해서 형변환이 의미하는 것은, 객체에 속한 멤버들에 대한 사용범위가 달라진다는 것을 의미합니다.
- 업캐스팅(upcasting) : (자식클래스의 인스턴스에 대한) 자식클래스의 타입의 레퍼런스 변수를 부모클래스 타입으로 형변환 하는 것. (타입변환 구문 생략 가능, 자동 형변환 됨)
- 다운캐스팅(downcasting) : (자식클래스의 인스턴스에 대한) 부모클래스 타입의 레퍼런스 변수를 자식클래스 타입으로 형변환 하는 것. (타입변환 구문 생략 불가, 형변환 타입을 명시해야됨)
- 형변환의 장점
- 여러 자식클래스 타입의 레퍼런스 변수들을 하나의 부모클래스 타입의 레퍼런스 변수로 다룰 수 있음
- 하나의 배열로 여러 자식클래스 객체 다룸
- 메소드의 매개변수를 부모클래스 타입 하나로 전달받아 사용할 수 있음
- 어떤 자식클래스 타입인지 알려면 instanceof 연산자로 구분
- 여러 자식클래스 타입의 레퍼런스 변수들을 하나의 부모클래스 타입의 레퍼런스 변수로 다룰 수 있음
객체지향 설계 원칙
- 단일 책임 원칙(SRP)
- 모든 클래스는 각각 하나의 책임만 가져야 한다는 원칙입니다.
- 모듈이 변경되는 이유가 한가지여야 함으로 받아들여야 한다. 여기서 변경의 이유가 한가지라는 것은 해당 모듈이 여러 대상 또는 액터들에 대해 책임을 가져서는 안되고, 오직 하나의 액터에 대해서만 책임을 져야 한다는 것
- 개방-폐쇄 원칙(OCP)
- 확장에는 열려있고 수정에는 닫혀 있어야 한다는 원칙이다. 기존의 코드는 잘 변경하지 않으면서도 확장은 쉽게 할 수 있어야 함.
- 개방 폐쇄 원칙을 지키기 위해서는 추상화에 의존하는 것이 중요
- 확장에는 열려있고 수정에는 닫혀 있어야 한다는 원칙이다. 기존의 코드는 잘 변경하지 않으면서도 확장은 쉽게 할 수 있어야 함.
- 리스코프 치환 원칙(LSP)
- 하위 타입은 상위 타입을 대체할 수 있어야 한다는 것이다. 즉, 해당 객체를 사용하는 클라이언트는 상위 타입이 하위 타입으로 변경되어도, 차이점을 인식하지 못한 채 상위 타입의 퍼블릭 인터페이스를 통해 서브 클래스를 사용할 수 있어야 한다는 것이다.
- 하위 클래스가 상위 클래스에서 선언한 기능을 위반하는 경우
- 상위 클래스가 주문 정렬을 위한 sortOrdersByAmount() 함수를 구현해두었는데, 하위 클래스에서 생성 날짜에 따라 정렬되도록 변경한 경우
- 하위 클래스가 입력, 출력 및 예외에 대한 상위 클래스의 계약을 위반하는 경우
- 상위 클래스에서 오류가 발생하면 null을, 값을 얻을 수 없으면 빈 컬렉션을 반환하게 해두었는데, 하위 클래스에서 오류가 발생하면 예외를 발생시키고, 값을 얻을 수 없을 때 null을 반환하도록 변경한 경우
- 상위 클래스에서는 입력 시 모든 정수를 허용하지만, 하위 클래스에서는 음수일 때 예외를 발생시키는 경우
- 상위 클래스에서 던지는 예외는 ArgumentException 뿐인데, 하위 클래스에서 다른 예외도 던지는 경우
- 하위 클래스가 상위 클래스의 주석에 나열된 특별 지침을 위반하는 경우
- 상위 클래스에 예금을 인출하는 withdraw() 메서드에 사용자의 출금 금액이 잔액을 초과해서는 안된다는 주석이 있을 때, 하위 클래스에서는 가능한 경우
- 인터페이스 분리 원칙(ISP)
- 하나의 일반적인 인터페이스보다 구체적인 여러 개의 인터페이스를 만들어야 한다는 원칙이다.
- 클라이언트의 목적과 용도에 적합한 인터페이스 만을 제공하는 것이다. 인터페이스 분리 원칙을 준수함으로써 모든 클라이언트가 자신의 관심에 맞는 퍼블릭 인터페이스(외부에서 접근 가능한 메세지)만을 접근하여 불필요한 간섭을 최소화할 수 있으며, 기존 클라이언트에 영향을 주지 않은 채로 유연하게 객체의 기능을 확장하거나 수정할 수 있다.
- 의존 역전 원칙(DIP)
- 비즈니스와 관련된 부분이 세부 사항에는 의존하지 않게 하는 것.
패러다임의 혼합
비즈니스 로직이나 서비스의 특징을 고려해서 패러다임을 정하는 것이 좋습니다. 하나의 패러다임을 기반으로 통일하여 서비스를 구축하는 것도 좋은 생각이지만 여러 패러다임을 조합하여 상황과 맥락에 따라 패러다임 간의 장점만 취해 개발하는 것이 좋습니다
Java 8 에서 왜 함수형 프로그래밍이 도입되었을까?
참조 절차지향 VS 객체지향 :: 불곰 (tistory.com) [OOP] 객체지향 프로그래밍의 5가지 설계 원칙, 실무 코드로 살펴보는 SOLID - MangKyu’s Diary (tistory.com)
Leave a comment