안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.
객체지향 3대 원칙
① 캡슐화
② 상속
③ 다형성
이 중 캡슐화에 대해서 알아보겠습니다.
☞ 캡슐화(encapsulation)
- 속성과 기능을 하나로 묶어서 관리 → class
- 속성의 접근제한자를 private으로 만들어 외부접근 차단
- 기능의 접근제한자를 public으로 만들어 기능(메소드)를 통해서만 속성을 사용하도록 제한
- 은닉화 기능 (외부에서 직접 접근하거나 변경할 수 없음)
즉, 연관된 속성과 기능을 하나의 클래스로 묶고 외부에서 쉽게 접근하지 못하도록 은닉하는 것!!
객체에 직접적인 접근을 막고 객체가 제공하는 필드와 메소드를 통해서만 접근 가능한 것입니다.
class 탄생 배경부터 알아보겠습니다.
클래스 탄생 배경
① 변수 : 하나의 값을 저장하기 위한 공간
→ 데이터 종류가 많아질수록 데이터의 개수만큼 변수명을 짓거나 관리하는 일이 버거워짐
② 배열 : 변수의 단점을 보완하고자 만든 문법요소로, 같은 자료형끼리 여러개의 데이터를 저장할 수 있음
→ 여러개의 자료형을 한 번에 관리하고 싶어짐
③ 구조체 : 배열의 단점을 보완하고자 만든 문법요소로, 서로 다른 자료형도 하나로 묶어서 관리 가능
→ 말 그대로 데이터만 묶어놓은 것으로 출력 기능, 계산 기능 등을 추가하고 싶어짐 + 치명적인 단점 확인
④ 클래스 : 다양한 자료형의 데이터를 묶어 관리할 수 있을 뿐만 아니라 데이터를 처리하는 다양한 기능까지 함께 관리하는 문법 요소
구조체는 자바에는 없는 문법 구조 이지만, 비슷하게 구현하여 구조체의 단점을 확인해보겠습니다.
만약 계좌 관리 프로그램을 만든다고 가정하였을 때, 입금/출금에 대해서 아래와 같이 코드를 짤 수 있습니다.
구조체 방식으로 계좌 관리 프로그램 생성
package com.ce.java;
public class Account {
String name;
long balance;
}
package com.ce.java;
public class AccountMain {
public static void main(String[] args) {
Account acc = new Account();
acc.name = "홍길동";
acc.balance = 1_000_000;
//구조체처럼 사용
//입금
acc.balance += 500_000;
System.out.println(acc.name + "님의 계좌 잔액은 " + acc.balance + "원 입니다.");
//출금
acc.balance -= 300_000;
System.out.println(acc.name + "님의 계좌 잔액은 " + acc.balance + "원 입니다.");
}
}
@콘솔출력값
홍길동님의 계좌 잔액은 1500000원 입니다.
홍길동님의 계좌 잔액은 1200000원 입니다.
홍길동님의 기존 잔액은 100만원이고, 50만원을 입금 / 30만원을 출금했다는 코드입니다.
하지만 여기서 만약 실수로 연산기호를 잘못 사용한다거나 금액을 잘못 입력하면 어떻게 될까요?
//구조체처럼 사용
//입금
acc.balance *= 500_000;
System.out.println(acc.name + "님의 계좌 잔액은 " + acc.balance + "원 입니다.");
//출금
acc.balance -= -300_000;
System.out.println(acc.name + "님의 계좌 잔액은 " + acc.balance + "원 입니다.");
@콘솔출력값
홍길동님의 계좌 잔액은 500000000000원 입니다.
홍길동님의 계좌 잔액은 500000300000원 입니다.
입금 시 연산기호를 += 대신 *=으로 잘못 입력하였고, 출금 시 -30만원을 뺐습니다.
엉뚱한 계산 결과가 나옵니다. 혹은 기존 잔액보다 더 많은 잔액을 출금한다고 하였을 때도 이상한 결과가 나오게 되죠.
//구조체처럼 사용
//입금
acc.balance += 500_000;
System.out.println(acc.name + "님의 계좌 잔액은 " + acc.balance + "원 입니다.");
//출금
acc.balance -= 2_300_000;
System.out.println(acc.name + "님의 계좌 잔액은 " + acc.balance + "원 입니다.");
@콘솔출력값
홍길동님의 계좌 잔액은 1500000원 입니다.
홍길동님의 계좌 잔액은 -800000원 입니다.
마이너스 통장이 아닌 일반 계좌 통장인데 계좌 잔액이 -80만원입니다...
이러한 문제가 생기는 이유는 구조체의 속성에 직접 접근하여 처리하기 때문입니다.
이를 해결하기 위하여 클래스의 캡슐화 속성을 이용하여 메소드를 통해서만 필드 값을 조정할 수 있도록 하면 될 것입니다.
클래스의 캡슐화 속성을 이용하여 계좌 관리 프로그램 생성
package com.ce.java;
public class Account {
//private 접근제한자 - 같은 클래스 내에서만 접근 가능
private String name;
private long balance;
public void setName(String name) {
this.name = name;
}
public void setBalance(long balance) {
this.balance = balance;
}
public String getName() {
return name;
}
public long getBalance() {
return balance;
}
}
package com.ce.java;
public class AccountMain {
public static void main(String[] args) {
Account acc = new Account();
acc.setName("홍길동");
acc.setBalance(1_000_000);
System.out.println(acc.getName() + "님의 계좌 잔액은 " + acc.getBalance() + "원 입니다.");
}
@콘솔출력값
홍길동님의 계좌 잔액은 1000000원 입니다.
속성에 대한 직접 접근을 막고 setter, getter메소드를 이용하여 값을 대입하고 리턴했습니다.
private은 같은 클래스 내에서만 접근할 수 있는 접근제한자로 AccountMain 클래스에서는 직접 접근이 불가합니다.
따라서 setter메소드에게 매개인자를 전달하여 setter메소드의 매개변수로 받아 속성 값을 대입하고,
getter메소드를 통해 해당 값을 return하게 하였습니다.
setter메소드에서의 this.는 현재 객체의 변수를 가르키는 숨은 참조 변수를 의미합니다.
변수는 가장 가까이 있는 것을 기준으로 하기 때문에 만약 this. 없이 name = name, balance = balance를 하게 된다면 넘어온 매개변수에 넘겨받은 매개변수 값을 대입하는 것이므로 대입을 하나마나의 효과가 나타나겠죠?
그러므로 현재 객체 Account의 객체에 있는 변수에 넘어온 매개변수의 값을 대입해라!를 시행하기 위해 this.을 해준 것입니다.
입금, 출금 메소드를 생성해보겠습니다.
public class Account {
private String name;
private long balance;
//입금메소드
public void deposit(long money) {
if(money > 0)
balance += money;
else
System.out.println("입금액이 유효하지 않습니다.");
}
//출금메소드
public void withdraw(long money) {
if(money <= balance)
balance -= money;
else
System.out.println("잔액이 부족합니다.");
}
public void setName(String name) {
this.name = name;
}
public void setBalance(long balance) {
this.balance = balance;
}
public String getName() {
return name;
}
public long getBalance() {
return balance;
}
}
public class AccountMain {
public static void main(String[] args) {
Account acc = new Account();
acc.setName("홍길동");
acc.setBalance(1_000_000);
System.out.println(acc.getName() + "님의 계좌 잔액은 " + acc.getBalance() + "원 입니다.");
//입금
acc.deposit(-500000);
System.out.println(acc.getName() + "님의 계좌 잔액은 " + acc.getBalance() + "원 입니다.");
//출금
acc.withdraw(3000000);
System.out.println(acc.getName() + "님의 계좌 잔액은 " + acc.getBalance() + "원 입니다.");
}
}
@콘솔출력값
홍길동님의 계좌 잔액은 1000000원 입니다.
입금액이 유효하지 않습니다.
홍길동님의 계좌 잔액은 1000000원 입니다.
잔액이 부족합니다.
홍길동님의 계좌 잔액은 1000000원 입니다.
이렇게 메소드를 이용하여 필드 값에 접근 해보았습니다.
연산기호가 잘못될 일도 없을 뿐더러, 출금 금액이 잔액보다 더 크거나 입금액이 0보다 작은 값이 대입되었을 때에 대한 상황을 해결할 수 있었습니다.
'Java > Java' 카테고리의 다른 글
변수) 변수 별 생명 주기 Liftcycle (0) | 2022.03.16 |
---|---|
변수) 전역변수(인스턴스 변수, static 변수), 지역변수 (0) | 2022.03.16 |
클래스와 객체) 클래스 내부/외부 구성요소, 객체지향형 프로그램(OOP) (0) | 2022.03.15 |
정렬 알고리즘) 값 교환, 순차 정렬, 선택 정렬 (0) | 2022.03.11 |
가변 인자(Variable Argument)란? (0) | 2022.03.11 |