객체 지향이란?
객체지향프로그래밍(Object Oriented Programming)

김모씨가 은행 계좌에 입금을 하고 출금을 한다. 그리고 또 최모씨의 계좌에 2만 원을 이체해 주려고 한다. 이 상황을 프로그램으로 어떻게 표현할 수 있을까?
이런 문제를 쉽게 해결할 수 있는 프로그래밍 방법이 바로 객체 지향 프로그래밍이다.

이 경우에는 Person이라는 객체와 BankAccount라는 객체를 만들 수 있다.
객체는 속성들과 동작들의 묶음이라고 할 수 있는데, 속성은 변수로 표현되고 동작은 함수로 표현된다.
Person과 BankAccount에는 어떤 속성들과 어떤 동작들이 있을 수 있을까?
Person 객체에는 이름, 나이, 보유 현금, 소유 계좌 등의 속성이 있을 것이다.
BankAccount에는 잔액, 소유인의 속성이 있다. 그리고 입금, 출금, 이체 등의 동작이 있다.

여기 p1이라는 사람 객체와 a1이라는 은행 계좌가 있다고 가정하자. p1의 이름은 문자열 "김신의", 나이는 28 그리고 보유 중인 현금은 정수 30000, 그리고 a1의 잔액은 100000 이렇게 하자. 이 두 객체는 어떤 관계가 있을까?
p1에게는 소유 계좌라는 속성도 있다. 이 소유 계좌가 바로 a1이다. 마찬가지로 a1의 소유인은 바로 p1이다.
그리고 a1에는 입금, 출금 등의 기능도 있어야 하는데 만약 입금을 하게 되면 p1의 현금 액수가 줄어들고 a1의 잔액이 늘 것이다. 반면에 출금을 하게 되면 a1의 잔액이 줄고 p1의 현금 액수가 그만큼 늘어난다.

자 이제 p2라는 사람 객체와 a2라는 은행 계좌 객체도 있다. a2는 p2의 소유 계좌이고 p2는 a2의 소유인이다.
a1에서 p2에게 2만 원을 계좌 이체해 주면 어떻게 될까? 그러면 a1의 잔액이 2만 원 적어지고 p2의 소유 계좌인 a2의 잔액이 2만 원 늘어날 것이다.
이렇게 정보와 동작들은 객체 단위로 묶고 객체를 연결하면서 프로그램을 짜는 것이 바로 '객체 지향 프로그래밍'이다.
Java와 더불어 Python, Ruby, C++, Swift, JavaScript 등 요즘 많이 쓰이는 언어들은 대부분 객체 지향 프로그래밍 언어이다. 전세계적으로 가장 많이 쓰이는 프로그래밍 방식이므로 열심히 배워 보도록 하자!
클래스 정리
개요
김모씨가 은행 계좌에 입금을 하고 출금을 하고, 또 최모씨의 계좌에 20,000원을 이체해주려고 한다. 이런 상황을 어떻게 프로그램으로 표현할 수 있을까?
일단 '사람'이라는 것을 표현할 방법이 필요하고, '계좌'라는 것을 표현할 방법이 필요하다. 그런데 현재까지 배운 자료형들(숫자형, 불린형, 배열 등)로는 완벽하게 표현해내기 어려울 것이다. 이런 상황을 쉽게 정리할 수 있는 프로그래밍 방법이 바로 객체 지향 프로그래밍이다.
이 경우에는 '사람'을 표현하는 객체와 '은행 계좌'를 표현하는 객체를 만들 수 있다. '객체'는 '속성'들과 '동작'들의 묶음이라고 할 수 있는데, 속성은 '변수'로 나타내고, 동작은 '메소드(함수)'로 나타낸다.
'사람' 객체에는 이름, 나이, 보유 현금, 소유 계좌 등의 속성들이 있을 것이다. 반면에 '은행 계좌'에는 잔액과 소유인이 속성으로 필요하고, 입금, 출금, 이체 동작들이 필요하다.
클래스(Class)
사람(Person)
'클래스'는 앞서 말한 객체들에 대한 설계도, 또는 설명서이다. '사람' 객체에 대한 설명서를 먼저 써보자.
public class Person {
String name;
int age;
int cashAmount;
// 은행 계좌?
}
Person이라는 클래스를 만들었다. 이 클래스에는 '이름'을 표현하는 name이라는 문자열 변수, '나이'를 표현하는 age라는 정수 변수, 그리고 '보유 현금'을 표현하는 cashAmount라는 정수 변수가 있다. '은행 계좌'를 표현하는 변수는 일단 비워두겠다.
은행 계좌(BankAccount)
이번에는 '은행 계좌' 객체에 대한 설명서를 써보자.
public class BankAccount {
int balancee;
// 소유인?
}
BankAccount라는 클래스를 만들고, 이 클래스에는 '잔액'을 표현하는 balance라는 정수 변수가 있다. '소유인'을 표현하는 변수는 일단 비워두겠다.
연결하기
이제 '사람'과 '은행 계좌'의 관계를 표현해보자.
public class Person {
String name;
int age;
int cashAmount;
BankAccount account;
}
BankAccount 클래스를 마치 자료형처럼 사용한 걸 볼 수 있다. account 변수는 BankAccount 타입을 갖게 된다.
마찬가지로:
public class BankAccount {
int balance;
Person owner;
}
owner. 변수는 Person 타입을 갖게 된다.
이런 식으로 프로그램을 객체 단위로 정리하고, 객체들끼리 엮으면서 프로그래밍 하는 방식이 바로 '객체 지향 프로그래밍'이다.
메소드 정리
개요
메소드는 클래스에 있는 함수이다. 자바에서 모든 함수는 클래스에 있기 때문에 사실 자바의 모든 함수는 메소드이다.
기본 문법(Syntax)
먼저 메소드의 기본 문법부터 보자.
int sum(int x, int y) {
return x + y;
}
sum이라는 메소드를 썼는데, 이 함수는 일단 파라미터로 정수형 x와 정수형 y를 받는다. 그리고 이 메소드는 꼭 정수형을 리턴시켜줘야 한다. 그렇지 않으면 오류가 나온다. return x + y;는 정수형을 리턴시켜주므로 문제 없다.
만약 리턴값이 없으면 자료형 대신 void라고 써주면 된다. 예를 들어서 예전에 썼던 main 함수도 리턴값이 없기 때문에 void를 썼었다.
public static void main(String[] args) {
System.out.println("Hello world!");
}
예제
'은행 계좌' 예제로 돌아가보자. '은행 계좌'에는 '입금' 기능, '출금' 기능, 그리고 '이체' 기능이 필요하다. 각각 틀만 써보자.
public class BankAccount {
int balance;
Person owner;
// 파라미터: 입금할 액수
// 리턴: 성공 여부 (불린)
boolean deposit(int amount) {
}
// 파라미터: 출금할 액수
// 리턴: 성공 여부 (불린)
boolean withdraw(int amount) {
}
// 첫 번째 파라미터: 받는 사람 (Person)
// 두 번째 파라미터: 이체할 금액 (정수)
// 리턴: 성공 여부 (불린)
boolean transfer(Person to, int amount) {
}
}
'입금' 기능은 deposit 메소드로 썼는데, 이 메소드는 파라미터로 입금할 액수 amount를 받고, 입금 성공 여부를 나타내는 불린 값을 리턴해준다.
'출금' 기능은 withdraw 메소드로 썼다. withdraw는 파라미터로 출금할 액수 amount를 받고, 성공 여부를 나타내는 불린 값을 리턴해준다.
마지막으로 '계좌 이체' 기능은 transfer 메소드로 썼다. transfer은 파라미터 두 개를 받는다:
- 첫 번째는 받을 사람을 나타내는 Person 타입의 to이다.
- 두 번째는 이체할 금액 amount이다.
다른 메소드들과 마찬가지로 리턴 값은 성공 여부를 나타내는 불린 값이다.
지금은 메소드에 아무 내용이 없고, 따라서 리턴 타입을 지키지 못했기 때문에 오류가 나오는데, 실제로 내용을 채워넣는 것은 인스턴스 강의 후에 할 예정이다.
인스턴스 정리
클래스가 '설계도'라면, 인스턴스는 그 설계도를 따른 '객체'를 뜻한다. 예를 들어서 Song이라는 클래스 있으면, '걱정말아요 그대', '거위의 꿈', '다행이다' 등은 Song 클래스를 따르는 인스턴스라고 부를 수도 있고, 편하게는 그냥 Song 인스턴스라고 부를 수 있다.
우리는 '은행 계좌 시뮬레이션' 프로그램에서는 Person이라는 클래스가 있는데, '김신의'라는 이름을 가진 Person 인스턴스, '문종모'라는 이름을 가진 Person 인스턴스, '성태호'라는 이름을 가진 Person 인스턴스 등이 있을 수 있다.
예제
실제로 인스턴스를 생성하는 방법을 보자. 일단 우리는 Person.java 파일과 BankAccount.java 파일밖에 없는데, 이 둘에는 main 메소드가 없다. main 메소드가 있어야 프로그램이 돌아갈 것이다. main 메소드를 쓰고 이런 저런 테스트를 하기 위해서는 BankDriver.java 파일을 만들겠다. (테스트용 클래스나 파일을 만들 때 'Driver'라는 단어를 자주 쓴다.)
public class BankDriver {
public static void main(String[] args) {
}
}
Person 인스턴스 생성
먼저 Person 인스턴스를 담는 변수를 만들어야 한다.
public class BankDriver {
public static void main(String[] args) {
// 사람 선언
Person p1;
}
}
실제로 Person 인스턴스를 만들기 위해서는 '생성자'라는 것을 써야하는데, 생성자에 대해서는 곧 자세히 배우므로, 일단은 '인스턴스를 생성하는 메소드' 정도로만 알고 있으면 된다.
생성자는 new 키워드와 함께 클래스의 이름을 써주면 된다.
public class BankDriver {
public static void main(String[] args) {
// 사람 선언
Person p1 = new Person();
}
}
이렇게 써주면 이제 p1에는 Person 인스턴스가 저장된다.
기억을 다시 되살려보면 Person 객체는 name 변수, age 변수, 그리고 cashAmount 변수가 있다. 각각의 변수에 값을 지정해준다.
public class BankDriver {
public static void main(String[] args) {
// 사람 선언
Person p1 = new Person();
p1.name = "김신의"
p1.age = 28;
p1.cashAmount = 30000;
}
}
제대로 들어갔는지 값들을 출력해볼까?
- 만약 BankAccount의 비어있는 메소드 오류 때문에 실행할 수 없다면, 해당 부분을 주석처리해 준다.
public class BankDriver {
public static void main(String[] args) {
// 사람 선언
Person p1 = new Person();
p1.name = "김신의"
p1.age = 28;
p1.cashAmount = 30000;
// 테스트
System.out.println(p1.name);
System.out.println(p1.age);
System.out.println(p1.cashAmount);
}
}
김신의
28
30000
사실 Person 인스턴스는 account라는 속성도 있는데, 아직 BankAccount 인스턴스가 없기 때문에 일단 두겠다.
BankAccount 인스턴스 생성
public class BankDriver {
public static void main(String[] args) {
// 사람 생성
Person p1 = new Person();
p1.name = "김신의"
p1.age = 28;
p1.cashAmount = 30000;
// 은행 계좌 생성
BankAccount a1 = new BankAccount();
a1.balance = 100000;
}
}
BankAccount 인스턴스를 생성하고 a1에 넣어주었다. 그리고 계좌 a1의 잔액을 100000으로 설정해주었다.
두 인스턴스 엮기
객체 지향 프로그래밍에서 중요한 부분은 연관된 객체들끼리 서로 엮는 것이다. 한 번 p1과 a1을 엮어보겠다.
public class BankDriver {
public static void main(String[] args) {
// 사람 생성
Person p1 = new Person();
p1.name = "김신의"
p1.age = 28;
p1.cashAmount = 30000;
// 은행 계좌 생성
BankAccount a1 = new BankAccount();
a1.balance = 100000;
// 두 객체의 관계 설정
p1.account = a1;
a1.owner = p1;
// 테스트
System.out.print(p1.name + "의 계좌 잔액: " + p1.account.balance);
}
}
김신의의 계좌 잔액: 100000
p1(Person 인스턴스)의 account 변수의 자료형은 BankAccount이다. p1.account에 BankAccount 인스턴스인 a1을 넣어줬다. 마찬가지로 a1.owner에는 Person 인스턴스인 p1을 지정해줬다. 즉 a1은 p1의 은행계좌이고, p1은 a1의 소유인인 셈이다.
실습과제
입금, 출금
메소드 연습
1. 입금
(1) 입금을 성공하면 true를 리턴, 실패하면 false를 리턴합니다.
(2) 입금 성공 시, 현재 잔고(balance)에 파라미터로 받은 금액(amount)을 더합니다.
(3) 입금 성공 시, 계좌주의 현금액(cashAmount)을 입금액만큼 줄입니다.
(4) 입금할 금액이 음수이면 입금 실패입니다(0원은 입금 성공).
(5) 계좌주의 현금이 입금액보다 작을 경우 입금 실패입니다.
(6) 입금 실패 시 다음과 같은 내용 출력:
입금 실패입니다. 잔고: xx원, 현금: xx원
(7) 입금 성공 시 다음과 같은 내용 출력:
xx원 입금하였습니다. 잔고: xx원, 현금: xx원
2. 출금
(1) 출금을 성공하면 true를 리턴, 실패하면 false를 리턴합니다.
(2) 출금 성공 시, 현재 잔고에서 파라미터로 받은 금액을 뺍니다.
(3) 출금 성공 시, 계좌주의 현금액을 출금액만큼 늘려줍니다.
(4) 출금할 금액이 음수이면 출금 실패입니다(0원은 출금 성공).
(5) 출금할 금액이 잔고보다 크면 출금 실패입니다.
(6) 출금 실패 시 다음과 같은 내용 출력:
출금 실패입니다. 잔고: xx원, 현금: xx원
(7) 출금 성공 시 다음과 같은 내용 출력:
xx원 출금하였습니다. 잔고: xx원, 현금: xx원
테스트
3. 인스턴스 생성
BankDriver 클래스의 main메소드에 수강생 이름과 나이로 새로운 Person 인스턴스를 만들어 p2라는 변수에 저장하세요. 그리고 p2에 해당하는 BankAccount 인스턴스 a2를 만들고 두 인스턴스를 연결해보세요. p2의 계정은 a2이고, a2의 소유인은 p2이어야 합니다.
초기 p2의 현금 보유량은 100,000원이고 a2의 잔액은 500,000원입니다.
4. 입출금
p2의 계좌인 a2에 대해 다음을 차례로 실행합니다:
(1) 30,000원 입금
(2) 170,000원 출금
(3) 620,000원 입금
(4) 890,000원 출금
30000원 입금하였습니다. 잔고: 530000원, 현금: 70000원
true
170000원 출금하였습니다. 잔고: 360000원, 현금: 240000원
true
입금 실패입니다. 잔고: 360000원, 현금: 240000원
false
출금 실패입니다. 잔고: 360000원, 현금: 240000원
false
BankAccount.java
public class BankAccount {
int balance;
Person owner;
// 파라미터 : 입금할 액수(정수)
// 리턴 : 성공여부(불린)
boolean deposit(int amount) {
// 1. write code here
if (amount < 0 || owner.cashAmount < amount) {
System.out.print("입금 실패입니다. 잔고: " + balance + "원, 현금: " + owner.cashAmount + "원");
return false;
} else {
owner.cashAmount = owner.cashAmount - amount;
balance = balance + amount;
System.out.print(amount + "원 입금하였습니다. 잔고: " + balance + "원, 현금: " + owner.cashAmount + "원");
return true;
}
}
// 파라미터 : 출금할 액수(정수)
// 리턴 : 성공여부(불린)
boolean withdraw(int amount) {
// 2. write code here
if (amount < 0 || balance < amount) {
System.out.print("출금 실패입니다. 잔고: " + balance + "원, 현금: " + owner.cashAmount + "원");
return false;
} else {
owner.cashAmount = owner.cashAmount + amount;
balance = balance - amount;
System.out.print(amount + "원 출금하였습니다. 잔고: " + balance + "원, 현금: " + owner.cashAmount + "원");
return true;
}
}
// 첫 번째 파라미터 : 받는 사람(Person)
// 두 번째 파라미터 : 이체할 금액(정수)
// 리턴 : 성공여부(불린)
// boolean transfer(Person to, int amount) {
// (다음 과제에서 사용하므로, 우선 skip합니다.)
// }
}
계좌 주인의 현금 보유량은 어떻게 표현할 수 있을까?
BankAccount 클래스에서 계좌 주인은 Person 자료형의 owner라는 변수이다. Person 클래스에서는 현금 보유량을 나타내는 int 자료형의 cashAmount라는 변수가 있다.
이를 종합하여 owner.cashAmount로 나타낼 수 있을 것이다.
Main.java
public class Main {
public static void main(String[] args) {
// 사람 선언
Person p1 = new Person();
p1.name = "김신의";
p1.age = 28;
p1.cashAmount = 30000;
// 은행 계좌 생성
BankAccount a1 = new BankAccount();
a1.balance = 100000;
p1.account = a1;
a1.owner = p1;
// 3 - 4. write code here
Person p2 = new Person();
p2.name = "유예진";
p2.age = 26;
p2.cashAmount = 100000;
BankAccount a2 = new BankAccount();
a2.balance = 500000;
p2.account = a2;
a2.owner = p2;
System.out.println(a2.deposit(30000));
System.out.println(a2.withdraw(170000));
System.out.println(a2.deposit(620000));
System.out.println(a2.withdraw(890000));
}
}
Person.java
public class Person {
String name;
int age;
int cashAmount;
BankAccount account;
}
'~2023.02 > Java' 카테고리의 다른 글
객체지향 프로그래밍 정리 (0) | 2022.03.19 |
---|---|
자바 기초 _ [토픽2] 자바 객체 지향 프로그래밍 _ 객체 설계하기 (0) | 2021.12.30 |
자바 기초 _ [토픽1] 자바 왕기초 _ 배열 (0) | 2021.12.29 |
자바 기초 _ [토픽1] 자바 왕기초 _ 조건문과 반복문 (0) | 2021.12.29 |
자바 기초 _ [토픽1] 자바 왕기초 _ 변수와 연산 (0) | 2021.12.26 |