Java에 대해 배우기 위해 그 근간이 되는 객체지향 프로그래밍과 관련 개념들에 대해 정리해보고자 합니다.
해당 포스트는 자바 공식홈페이지를 참고(번역?)했습니다.
What is an Object?
프로그래밍을 해봤으면, 객체지향 프로그래밍(Object-Oriented Programming, OOP)이라는 것에 대해 한번 쯤은 듣게 됩니다.
가장 먼저, OOP에서 객체(Object)가 무엇인지에 대해 간략히 정리를 해보고자 합니다.
객체란, 서로 관련된 상태와 행동을 하나로 묶어놓은 소프트웨어의 번들입니다.
이러한 객체는 모두 상태(state)와 행동(behavior)이 있다는 특징을 가지고 있습니다.
예를 들어,
개라는 객체는 이름, 색깔, 품종, 배고픔정도와 같은 상태와, 짖고, 꼬리를 흔들고, 물건을 가져오는 행동들을 가지고 있습니다.
자전거라는 객체는 현재 기어, 현재 스피드와 같은 상태와, 기어를 바꾸고, 브레이크를 잡는 것과 같은 행동들을 가지고 있습니다.
이렇게 실생활에 있는 객체를 가지고,
1) 이 객체는 어떤 상태를 가지고 있을 수 있는가?
2) 이 객체는 어떤 행동들을 할 수 있는가?
라는 두가지 질문을 하는 것이 매우 중요하며, 실생활에 있는 객체들을 관찰하고 위의 질문들을 던지는 것이 OOP의 시작점이 될 수 있을 것입니다.
앞서 설명한 것처럼, 소프트웨어 객체는 관련된 상태와 행동 두가지로 구성되게 됩니다.
객체는 상태(state)를 fields(혹은 variables, 변수)에 저장하고, 행동(behavior)은 methods(혹은 function, 함수)를 통해 노출시킵니다.
여기에서 메소드(methods)는 객체 내부 상태를 관리하고, 객체간 통신을 위한 기본적인 메커니즘 역할을 합니다.
내부 상태는 숨기고, 객체의 메소드를 이용하여 모든 상호작용들을 수행하는 방식을 데이터 인캡슐레이션(Data Encapsulation)이라고 하며, 이것은 OOP의 근간이 되는 원칙중 하나입니다.
OOP방식, 하나의 소프트웨어 객체로 코드를 번들링하는 것은 아래와 같은 장점을 제공해줍니다.
- Modularity: 하나의 객체로 작성된 소스코드는 독립적으로 작성되고, 유지보수가 가능합니다. 일단 생성되면, 해당 객체는 손쉽게 다른 곳에서 사용이 가능합니다.
- Information-hiding: 오직 객체의 메소드만으로 상호작용(interact)함으로써, 내부 구현 코드나 바깥에서 알 필요가 없는 정보들을 숨길 수 있게 됩니다.(encapsulation)
- Code re-use: 다른 개발자가 기존에 만들어 놓은 객체가 이미 존재한다면, 내가 작성한 프로그램에서 손쉽게 해당 객체를 사용할 수 있습니다. 이를 통해, specialists들은 복잡한 태스크단위의 객체를 구현, 테스트, 디버그 할 수 있으며, 내가 작성한 코드또한 믿을 수 있게 됩니다.
- Pluggability and debugging ease: 만약 특정 객체가 문제가 있는 것으로 판별된다면, 매우 손쉽게 해당 객체를 application으로부터 제거하고, 다른 객체로 대체할 수 있습니다. 이것은 볼트가 부서지면 다른 볼트로 대체하는 실생활의 메커니즘과 매우 비슷합니다.
What is a Class?
클래스란 무엇 일까요?
application에서, 같은 종류의 많은 개별 객체들을 찾아 볼 수 있습니다.
예를 들어, 같은 모델, 같은 색깔, 같은 제조사를 가진 수많은 자전거가 존재 할 수 있습니다.
이 각각의 자전거들은 같은 설계도면을 통해 만들어졌고, 따라서 똑같은 컴포넌트들로 구성되어 있습니다.
객체지향 용어로써, 우리는 이 자전거를 자전거라는 클래스의 인스턴스 라고 하고,
자전거들을 만드는데 사용된 자전거 설계도면을 클래스라고 부릅니다.
아래의 코드 snippet은 자전거 클래스의 예시입니다.
class Bicycle {
int cadence = 0;
int speed = 0;
int gear = 1;
void changeCadence(int newValue) {
cadence = newValue;
}
void changeGear(int newValue) {
gear = newValue;
}
void speedUp(int increment) {
speed = speed + increment;
}
void applyBrakes(int decrement) {
speed = speed - decrement;
}
void printStates() {
System.out.println("cadence:" +
cadence + " speed:" +
speed + " gear:" + gear);
}
}
changeCadence, changeGear, speedUp, applyBrakes, printStates와 같은 메소드들은 bicycle의 behavior을 의미하게 됩니다.
그리고 이 메소드를 통해 우리는 바깥 세계와 상호작용(interact)하게 됩니다.
또한 여기서 봐야 할 추가적인 사항은 class에는 main() method가 존재하지 않는다는 것입니다.
이는 위의 클래스가 application이 아니라, 말그대로 청사진(설계도)에 불가하기 때문입니다.
새로운 Bicycle 객체를 생성하고, 사용하는 책임은 applcation의 다른 클래스에 속하게 됩니다.
아래의 BicycleDemo 클래스는 두개의 개별 Bicycle 객체를 생성하고, 그들의 메소드들을 호출합니다.
class BicycleDemo {
public static void main(String[] args) {
// Create two different
// Bicycle objects
Bicycle bike1 = new Bicycle();
Bicycle bike2 = new Bicycle();
// Invoke methods on
// those objects
bike1.changeCadence(50);
bike1.speedUp(10);
bike1.changeGear(2);
bike1.printStates();
bike2.changeCadence(50);
bike2.speedUp(10);
bike2.changeGear(2);
bike2.changeCadence(40);
bike2.speedUp(10);
bike2.changeGear(3);
bike2.printStates();
}
}
위의 방식대로 각 자전거 객체의 메소드를 호출한 결과는 아래와 같을 것입니다.
cadence:50 speed:10 gear:2
cadence:40 speed:20 gear:3
What is Inheritance?
다른 종류의 객체들이라 할 지라도 종종 공통점을 가지고 있는 것을 볼 수 있습니다.
산악 자전거, 로드 자전거, 2인용 자전거와 같은 것이 그 예가 될 수 있을 것입니다.
이 자전거들은 모두 일반 자전거의 특징들을 가지고 있습니다.(현재 속도, 현재 패달 회전수, 현재 기어)
하지만, 각각의 자전거들은 그들만의 고유한 추가적인 특징들을 가지고 있습니다.
2인용 자전거라면, 당연히 2개의 좌석과 두개의 핸들바가 존재할 것이고,
로드 자전거는 아래로 휘어져 있는 핸들바를, 산악 자전거는 추가적인 체인링이 있어 더 낮은 기어단계로 조절 할 수 있을 것입니다.
OOP에서는 일반 자전거의 특징들 처럼 여러 클래스들에서 공통되는 부분들을 상속하는 것이 가능합니다.
위의 예를 계속 이용하자면,
Bicycle이라는 클래스는 이제 로드 자전거, 2인용 자전거, 산악 자전거의 부모 클래스(superclass)가 되게 됩니다.
자바라는 언어에서, 각각의 클래스는 하나의 부모 클래스(superclass)를 가지는 것이 가능하고, 각각의 부모클래스는 수많은 부모클래스를 가지는 것이 가능합니다.
위 이미지는 자전거 클래스의 계층 구조를 보여줍니다.
하위 클래스를 만드는 문법은 매우 간단합니다. 아래처럼 MountainBike 클래스를 선언하고, extends 키워드와 superclass명을 입력해주면 됩니다.
class MountainBike extends Bicycle {
// new fields and methods defining
// a mountain bike would go here
}
이렇게 상속을 통해서 MountineBike는 Bicycle의 모든 fields와 메소드들을 상속 받을 수 있게 되면서도, 해당 클래스 고유의 필드나 메소드를 따로 정의할 수 있게됩니다.
이를 통해서, 자식클래스의 코드 가독성을 높일 수 있지만, 해당 코드에서 보여지지 않는 부모클래스의 상태와 메소드를 관리하는 것에 주의를 기울여 줘야 합니다.
What is an Interface?
앞서 설명한 것처럼 객체들은 객체 바깥세계와 상호작용하기 위해 노출되어져 있는 메소드를 사용합니다.
메소드는 객체와 외부세계와의 인터페이스를 형성합니다.
예를 들어, 텔레비전 세트앞에 위치한 버튼들은 당신과 플라스틱케이스 안쪽에 존재하는 전기배선 사이의 인터페이스 입니다.
만약 내가 전원버튼을 누른다면, 텔리비젼은 꺼졌다가 켜지게 됩니다.
가장 공통적인 형태로써, 인터페이스는 body가 비어있는 관련된 메소드들의 집합입니다.
만약, 앞서 우리가 다뤄봤던 자전거의 인터페이스를 만든다면 아래와 같을 것입니다.
interface Bicycle {
// wheel revolutions per minute
void changeCadence(int newValue);
void changeGear(int newValue);
void speedUp(int increment);
void applyBrakes(int decrement);
}
위의 인터페이스를 구현하려고 한다면, 클래스명을 바꾸고, implements 키워드를 아래처럼 사용하면 됩니다.
class ACMEBicycle implements Bicycle {
int cadence = 0;
int speed = 0;
int gear = 1;
// The compiler will now require that methods
// changeCadence, changeGear, speedUp, and applyBrakes
// all be implemented. Compilation will fail if those
// methods are missing from this class.
void changeCadence(int newValue) {
cadence = newValue;
}
void changeGear(int newValue) {
gear = newValue;
}
void speedUp(int increment) {
speed = speed + increment;
}
void applyBrakes(int decrement) {
speed = speed - decrement;
}
void printStates() {
System.out.println("cadence:" +
cadence + " speed:" +
speed + " gear:" + gear);
}
}
쉽게 말해서 인터페이스는 클래스와 외부세계와의 계약서같은 존재입니다. 이 계약서에는 클래스가 특정 인터페이스를 구현한다고 주장하는 경우, 인터페이스에 명시되어 있는 모든 메소드들은 반드시 해당 클래스에도 정의되어져야 한다고 정해져 있습니다.
이 부분에 대해서는 추후 다시 다루도록 하겠습니다.
What is a Package?
패키지란, 관련된 클래스와 인터페이스들을 정리해서 모아놓은 namespace입니다.
컴퓨터의 폴더를 생각하면 이해가 쉬울 수 있습니다. 아마 image들은 이미지 폴더에, HTML 페이지들을 HTML폴더에서 관리를 하는 것이 일반적일 것입니다.
Java언어로 작성된 소프트웨어는 수백, 수천개의 클래스들로 구성될 수 있으므로 관련 인터페이스 및 클래스들을 하나의 패키지에 배치하여 관리하는 것이 중요합니다.
자바 플랫폼은 수 많은 class library(i.e. 패키지)들을 제공하고 있습니다.
이 라이브러리들이 바로 API(Application Programming Interface)라고 불리는 녀석들입니다.
패키지는 범용적인 프로그래밍과 관련된 작업들을 나타냅니다.
예를 들어, String Object는 문자열의 상태와 행동에 관한 것들을 포함하고 있고,
File Object는 프로그래머들이 파일을 쉽게 생성, 삭제, 조사, 비교, 변경 할 수 있는 filesystem을 가지고 있습니다.
Socket Object는 네트워크 소켓의 생성 및 사용을 용이하게 해줍니다.
그리고 이러한 클래스들은 말그대로 수천개 이상이 있기에, 프로그래머들은 내가 만드는 특정 application의 디자인에만 집중을 할 수 있습니다.
The Java Platform API Specification는 모든 패키지, 인터페이스, 클래스, 메소드들에 대한 모든 정보를 가지고 있습니다.
이 페이지에 북마크를 걸어놓고 필요한게 있을 때마다 찾는다면 많은 도움이 될 것입니다.
'java,springboot' 카테고리의 다른 글
vscode에서 gradle로 springboot 개발환경 설정 (0) | 2023.03.01 |
---|---|
parameter 1 of constructor in required a bean of type that could not be found (0) | 2023.02.27 |
Ljava.lang.Object 읽을 수 있게 만들기(List 타입 콘솔 찍기) (0) | 2023.02.17 |
@Value 와 @ConfigurationProperties 이용해 여러 프로퍼티 파일(yml) 설정 (0) | 2023.02.13 |
Maven vs Gradle? (0) | 2023.01.26 |