일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 백준 2504번
- 플로이드 워셜 알고리즘(Floyd-Warshall Algorithm)
- DFS
- BFS(Breadth First Search)
- 백준 2812번
- DFS & BFS
- 백준 21606번
- 동적 프로그래밍(Dynamic Programming)
- 백준 10000번
- 큐(Queue)
- 백준 1707번
- 다익스트라 알고리즘(Dijkstra Algorithm)
- 백준 18352번
- 그리디 알고리즘(Greedy Algorithm)
- 트리(Tree)
- 알고리즘 개념
- 백준 2261번
- 백준 2493번
- 백준 17608번
- 스택(Stack)
- 그래프(Graph)
- 이분 그래프(Bipartite Graph)
- 분할 정복(Divide and Conquer)
- 위상 정렬(Topological Sort)
- 이분 탐색(Binary Search)
- 백준 9012번
- 위상 정렬(Topology Sort)
- 백준 1948번
- DFS(Depth First Search)
- BFS
- Today
- Total
Always Be Wise
객체 지향 프로그래밍 본문
객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위,
즉 "객체"들의 모임으로 파악하고자 하는 것을 의미합니다.
객체 지향 프로그래밍의 중요한 특징은 아래와 같습니다.
캡슐화(Encapsulation)
캡슐화란 데이터와 코드의 형태를 외부로부터 알 수 없게하고,
데이터의 구조와 역할, 기능을 하나의 캡슐 형태로 만드는 방법을 의미합니다.
캡슐화의 중요한 목적은 변수를 Private로 선언하여 데이터를 보호하고,
보호된 변수는 Getter나 Setter 등의 메소드를 통해서만 간접적으로 접근을 허용하는 것입니다.
캡슐화를 하면 불필요한 정보를 감출 수 있어 정보 은닉을 할 수 있습니다.
추상화(Abstraction)
추상화는 객체의 공통적인 속성과 기능을 추출하여 정의하는 것을 의미합니다.
클래스는 객체들이 어떤 특징들이 있어야 한다고 정의하는 추상화된 개념입니다.
상속(Inheritance)
상속이란 기존 상위 클래스의 코드를 재사용 및 확장하는 것을 의미합니다.
상위 클래스와 하위 클래스는 [하위 클래스 Is a kind of 상위 클래스] 관계가 성립합니다.
다형성(Polymorphism)
다형성이란 한 객체가 상속을 통해 기능을 확장하거나 변경하여 다른 여러 형태로 재구성되는 것을 의미합니다.
오버로딩(Overloading)와 오버라이딩(Overriding)이 다형성의 대표적인 예라고 할 수 있습니다.
오버로딩은 사전적으로 ‘과적하다'라는 의미로, 하나의 클래스 내에 이미 사용하려는 것과 같은 이름을 가진 메소드가 있더라도
매개 변수의 수나 타입을 다르게하여 새롭게 정의하는 것을 의미합니다.
오버라이딩은 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의하는 것을 의미합니다.
자식 클래스에서는 오버라이딩하고자 하는 메소드의 이름, 매개 변수, 리턴 값이 모두 같아야 합니다.
객체 지향 프로그래밍은 위 네 가지 특성을 통해서 어떤 대상을 추상화하여 공통점을 찾고,
그것을 캡슐화하여 객체를 만들고, 새로운 객체가 상속받아 재사용이 가능하게 만들어 줍니다.
또한, 상속받은 객체는 다형성을 통해 기능을 수정 또는 추가하여 재사용할 수 있습니다.
결국 이를 통해 코드의 재사용성이 높아지고, 유지보수가 편리해지는 장점이 있습니다.
SOLID 원칙
단일 책임 원칙(SRP, Single Responsibility Principle)
한 클래스는 하나의 책임만 가져야 한다는 원칙을 의미합니다. 예를 들어, 아래와 같이 Developer라는 클래스가 있다고 가정해봅시다.
public class Developer {
private final static boolean BACKEND = true;
private final static boolean FRONTEND = false;
private final boolean role;
public void work() {
if (this.role == BACKEND) {
...
} else {
...
}
}
}
Developer 클래스의 work 메소드는 role이 무엇인지에 따라(BACKEND와 FRONTEND) 서로 다른 구현을 갖습니다.
이는 단일 책임 원칙을 위반하는 것입니다. 해당 클래스를 상속하는 BackendDeveloper, FrontendDeveloper 클래스를 각각 만들어
기능을 구현한다면 단일 책임 원칙을 지킬 수 있습니다.
이렇게 클래스를 분리해 놓으면, 특정 클래스가 바뀌더라도 다른 클래스에는 영향이 가지 않습니다.
이처럼 변경이 있을 때 파급 효과가 적다면 단일 책임 원칙을 잘 따른 것이라고 판단할 수 있습니다.
개방 폐쇄 원칙(OCP, Open/Closed Principle)
확장에는 열려있으나 변경에는 닫혀 있어야 한다는 원칙을 의미합니다.
public interface CalculatorOperation {
void perform();
}
public class Addition implements CalculatorOperation {
private double left;
private double right;
private double result;
// constructor, getters and setters
@Override
public void perform() {
result = left + right;
}
}
public class Calculator {
public void calculate(CalculatorOperation operation) {
if (operation == null) {
throw new InvalidParameterException("Cannot perform operation");
}
operation.perform();
}
}
위의 예시에서 CalculatorOperation 인터페이스를 구현하는 Addition 클래스가 있을 때, 다른 연산 클래스들이 추가로 구현되더라도
Calculator 클래스의 코드는 변경할 필요가 없습니다. 기존에 사용하던 인터페이스를 구현한 새로운 클래스를 만들어주면 됩니다.
리스코프 치환 원칙(LSP, Liskov Subsitution principle)
부모 클래스의 인스턴스를 사용하는 위치에서 자식 클래스의 인스턴스도 사용할 수 있어야하는 원칙을 의미합니다.
예를 들어, 동물이라는 부모 클래스와 고양이라는 자식 클래스가 있을 때, 동물 클래스에서의 먹다라는 메소드와
고양이 클래스에서의 먹다라는 메소드가 형식적, 내용적 측면에서 원래의 형태와 의도를 위반하지 않아야 합니다.
인터페이스 분리 원칙(ISP, Interface Segregation Principle)
특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다는 원칙을 의미합니다.
구현체는 한 개의 범용 인터페이스 사용으로 불필요한 메소드들을 가질 필요가 없습니다.
예를 들어, Payment 인터페이스를 Loan 인터페이스와 Bank 인터페이스로 분리한다면 Bank 인터페이스에 수정이 발생해도
Loan 클라이언트에게는 영향을 주지 않습니다. Loan 클라이언트는 Loan 인터페이스에 있는 메소드들과 의존 관계를 맺기 때문입니다.
의존관계 역전 원칙(DIP, Dependency Inversion Principle)
추상화에 의존해야지 구체화에 의존하면 안된다는 원칙을 의미합니다.
예를 들어, 자동차와 타이어의 관계에서 타이어는 소모품이고 계절에 따라 교체될 수 있습니다.
따라서 자동차와 타이어의 관계를 설정할 때 자동차가 스노우 타이어라는 구체 클래스에 의존하는 것보다는 스노우 타이어, 일반 타이어,
광폭 타이어가 구현하고 있는 타이어라는 인터페이스를 새로 정의하고, 자동차는 타이어 인터페이스를 의존하게 해야 합니다.
- SRP: 어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 합니다.
- OCP: 자신의 확장에는 열려 있고, 주변의 변화에 대해서는 닫혀 있어야 합니다.
- LSP: 서브 타입은 언제나 자신의 기반 타입으로 교체할 수 있어야 합니다.
- ISP: 클라이언트는 자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안됩니다.
- DIP: 자신보다 변하기 쉬운 것에 의존하지 말아야합니다.
'기술 관련 정리' 카테고리의 다른 글
Monolithic Architecture and Micro Service Architecture (0) | 2022.06.10 |
---|---|
프로그래밍 패러다임 (0) | 2022.06.10 |
트랜잭션이란? (0) | 2022.04.12 |
정렬 알고리즘 - 계수 정렬(Counting Sort) (0) | 2022.04.09 |
정렬 알고리즘 - 힙 정렬(Heap Sort) (0) | 2022.04.09 |