객체지향 프로그래밍
객체란 무엇인가?
객체는 여러 개로 정의되어 있다.
- 소프트웨어 세계에 구현할 대상이며 속성과 기능을 가지는 프로그램 단위
- 이름(name)과 값(value)으로 구성된 프로퍼티(property)의 정렬되지 않은 집합
- 어떠한 속성값과 행동을 가지고 있는 데이터
- 상태와 행동을 함께 지닌 실체
속성값과 기능을 가지는 데이터라고 정의할 수 있겠다.
객체지향의 사실과 오해
객체를 설명할 때 쉬운 이해를 위해 현실의 사물에 빗대어 설명하곤 한다.
이해하는 데에 도움은 되지만 완벽히 같은 개념은 아니다.
책 객체지향의 사실과 오해
에 따르면 객체는 협력적이고, 자율적이여야 한다.
객체는 다른 객체의 요청을 받아들일 수 있는 상태여야 하며, 요청을 응할지, 어떤 방식으로 응답할지는 객체 스스로 판단한다.
현실의 사물과 다른 가장 큰 이유다.
현실에서 음료수 캔을 객체 B라고 가정하자. 사람이라는 객체 A는 음료수 캔을 따려고 한다.
A가 B을 딸 때, B가 스스로 뚜껑을 딴 것인가?
아니다. 뚜껑이 A에 의해 열렸다.
그렇다면 디지털 세계에서는 어떨까?
A가 B를 따기 위해서는 B에게 요청을 보내야 한다.
요청을 받은 B는 스스로 뚜껑을 연다.
객체지향과 절차지향
절차지향
- 문제를 여러 개의 함수로 나누어서 처리한다.
- 프로시저와 데이터 간의 접근이 자유롭다.
- 처리 속도와 실행 속도가 빠르다.
- 캡슐화가 저하되어 유지보수가 어렵다.
ex. C언어
객체지향
- 문제를 여러 개의 객체로 나누어서 처리한다.
- 코드 재사용이 용이하다.
- 유지보수가 쉽다.
- 처리 속도가 상대적으로 느리다.
- 객체가 많으면 용량이 커진다.
ex. JAVA, Python, C#
객체지향프로그래밍 특징
4가지 특징(캡슐화
, 상속
, 추상화
, 다형성
) 을 가지고 있다.
캡슐화
- 관련된 필드와 메서드를 하나로 묶는다.
- 실제 구현내용을 외부로부터 숨긴다.
- 외부에서는 공개된 메서드를 통해 접근할 수 있다.
- 외부에 영향 없이 객체 내부의 구현을 변경할 수 있다.
캡슐화는 기능을 외부에게 감추고, 기능을 사용하는 코드에 영향을 주지 않고 내부 기능을 변경할 수 있는 유연함을 가진다.
캡슐화를 위한 규칙
Tell, Don't Ask
- 묻지 말고 시켜라
1
2
3
4
5
if(acc.getMemberShip() == REGULAR) {...}
// 묻고 있다. -> 외부에서 값을 직접 확인하고 있다.
if (acc.hasRegularPermission()){...}
// 시킨다. -> 외부에서 값을 확인시키고 있다.
Demeter's Law
- 외부에 자료를 숨기는 대신(필드값을 공개하지 않는 대신) 함수를 공개
- 외부에서 어떤 자료를 가지고 있는지 몰라야 한다.
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
32
33
34
35
36
37
38
39
40
41
42
// 잘못된 예시
public class Address {
private String region;
private String details;
public String getRegion(){
return region;
}
}
@Service
public class RegionService {
public boolean checkSeoulRegion(final Address address) {
if("서울".equals(address.getRegion())) {
return true;
}
}
}
---
// 올바른 예시
public class Address {
private String region;
private String details;
public boolean isSeoulRegion() {
return "서울".equals(region);
}
}
@Service
public class RegionService {
public boolean checkSeoulRegion(final Address address) {
if(address.isSeoulRegion()) {
return true;
}
}
}
상속
- 상위클래스의 모든 것을 하위 클래스가 이어받는다.
- 이는 코드의 중복을 없애고 개발단계와 유지보수 단계에서의 비용을 줄여준다.
상속보단 조립
- 현재는 상속보다는 조립의 형태로 권장되고 있다.
- 상속의 문제점
조립
- 여러 객체를 묶어서 더 복잡한 기능을 제공할 수 있다.
- 필드로 다른 객체를 참조하는 방식으로 조립 또는 객체를 필요 시점에 생성한다. -> 진짜 하위 타입인 경우에만 상속을 사용해야 한다.
1
2
3
4
5
6
7
8
9
public class FlowController {
private Encryptor encryptor = new Encryptor(); // 필드로 조립
public void process(){
...
byte[] encryptedDate = encryptor.encrypt(date);
...
}
}
Spring 프레임워크의 IOC 컨테이너가 조립의 개념을 사용한다.
추상화
- 객체에서 공통된 속성과 행위를 추출하는 기법이다.
- 복잡한 것을 이해하기 쉽게 단순화시킨다.
- 어떻게?
- 객체들 간의 공통점은 취하고 차이점은 버리는 일반화를 통해 단순하게 만든다.
- 중요한 부분을 강조하기 위해 불필요한 세부 사항을 제거함으로써 단순하게 만든다.
타입 추상화
다형성
오버 로딩(overloading)
- 사전적으로는
과적하다
라는 뜻이다. - 동일한 메서드 이름의 존재를 허용하는 JAVA에서 사용된다.
자바의 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메소드가 있더라도 매개변수의 개수 또는 타입이 다르면, 같은 이름을 사용해서 메소드를 정의할 수 있다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class OverloadingMethods {
public void print() {
System.out.println("오버로딩1");
}
String print(Integer a) {
System.out.println("오버로딩2");
return a.toString();
}
void print(String a) {
System.out.println("오버로딩3");
System.out.println(a);
}
String print(Integer a, Integer b) {
System.out.println("오버로딩4");
return a.toString() + b.toString();
}
}
오버 라이딩(overriding)
- 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의한다.
부모 클래스의 메소드를 재정의하는 것이므로, 자식 클래스에서는 오버라이딩하고자 하는 메소드의 이름, 매개변수, 리턴 값이 모두 같아야 한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Person {
void greet() {
System.out.println("안녕하세요.");
}
}
class Child extends Person {
@Override
protected void greet() {
System.out.println("안녕");
}
}
class American extends Person {
@Override
public void greet() {
System.out.println("hello");
}
}
누군가가 물어본다면
객체란 데이터(속성)와 그 데이터를 처리하는 함수(메서드)를 함께 묶어 놓은 것입니다.
객체는 클래스라는 틀에서 생성되며, 이 클래스는 객체의 구조와 행동을 정의합니다.
또한 객체 지향 프로그래밍(OOP)의 기본 단위로, 객체 지향 프로그래밍은 캡슐화, 상속, 추상화, 다형성 의 4가지 특성을 가집니다.
객체는 클래스라는 틀에서 생성되며, 이 클래스는 객체의 구조와 행동을 정의합니다.
또한 객체 지향 프로그래밍(OOP)의 기본 단위로, 객체 지향 프로그래밍은 캡슐화, 상속, 추상화, 다형성 의 4가지 특성을 가집니다.
This post is licensed under CC BY 4.0 by the author.