😵 ~23.11.10

0704 | 객체 지향 프로그래밍

unikue 2023. 7. 5. 16:45

 

 

0406 | 객체지향 프로그래밍_강의 한줄요약 (1) // 캡슐화, 코드분리, 클래스구현, has a 상속, 코드

[1] 캡슐화 = 객체지향의 초석. 데이터 구조와 함수를 하나의 영역에 함께 정의하는 것이 목표. : 프로그램 = 절차 ▶ 함수 개체가 많아지는 문제로 수납법 모색 ▶ 수납 공간 = 클래스파일 ▶ 기능

ala-nueva.tistory.com

 

▲ 사전 예습 포스팅

 


 

 

✅ 객체지향

프로그램에서 표현하고자 하는 실세계의 일들을 객체를 사용해서 모델링

(* 모델링 = 설계. 거시적으로 기본 방식의 구현 틀을 만들어냄) object can be a combination of variables, functions, and data structures

객체 지향 보다는 객체부터 시작하는 프로그래밍이라 생각하자!

 


✅ 캡슐화
상속, 추상화
다형성 (인터페이스에서 진행)

 


✅ 객체지향 이전의 캡슐화
- 함수의 개체수가 많아지는 문제 ▶ 어떻게 수납할것인가? ▶ 클래스파일에 수납
- 기능별로 나누는것보다 데이터별로 나누는게 내가 다루는 데이터를 분명하게 보여줄 수 있다 객체지향 필요성

- 하지만 이 데이터를 외부에서 사용하게 될 경우 데이터가 영향을 받으면 안된다. (*구조화된 객체를 사용하는 함수는 객체의 구조변경에 아주 취약하다)  캡슐화 필요성
- 지역변수 안에 쓰이는 기존의 변수명은 내가 손댈 수 없음. 외부에서 수정하게되면 끌어다 쓴 내 코드까지 영향을 받게 됨 printf("...", eclipse.x); // 이 코드는 기존코드 eclipse에서 가져다 썼으므로 변동되면 영향을 받는다.

 

 


 


따라서 함수(= 코드를 나누는 도구) 형태의 프로그램을 만들고 있음에도 불구하고 동일 데이터끼리 묶어놓게 됨. (기능 + 속성)
캡슐화를 하면 데이터 구조에 따른 코드의 수정범위를 캡슐 범위로 한정할 수 있다

#️⃣ 함수 정리:  데이터 구조와 함수를 하나의 영역에 함께 두는 방법이 바람직
▶ 함수만 남아있는게 우리가 보는 형태랑 잘 맞지않음 
▶ 캡슐화를 해도 갖다 써버리면 캡슐이 깨지는 행위가 발생

#️⃣ 캡슐을 깨뜨리는 행위를 막을 수 있는 도구  은닉성
private으로 해놓으면 외부의 클래스가 해당 클래스의 기능을 사용할 수 없음 ▶접근 제어 지시자 사용
default는 같은 패키지에 있을경우 public과 동일. 다른 패키지면 둘의 기능이 다름.
protected 상속과 추상화를 할 때 추가로 설명 들을 예정

 

 

코드가 어떤 형태를 띄었든 결국 객체화 (객체가 가진 특성을 사용하는 형태)로 귀결된다

 

 


✅ 객체지향의 캡슐화

: 구조적인 프로그래밍에서는 캡슐화라는 표현을 하지 않는다.
: 객체지향은 코딩이아니라 설계. 구조. (구조적인 프로그래밍은 좀더 미시적인 구조. 객체지향은 큰 구조.)
: 객체지향은 실세계 기반이므로 인간의 표현식에 맞게 꾸리는 것.
: '오목판을 출력한다' ▶ 이 문장을 코딩으로 하는게 실세계 코딩

 

#️⃣ 객체지향적 캡슐화

- 역할과 책임을 모두 객체에게 주면서 캡슐로 묶은 것. 설계하는데 필요한 속성과 기능을 묶어주고 외부의 영향을 막는 것.

 

#️⃣ 물리적인 캡슐화

- 접근제한자를 통해서 물리적인 제한을 준다

 

객체지향 캡슐화가 깨지는 경우 ▼

더보기

자바의 객체지향 프로그래밍에서 캡슐화(Encapsulation)는 클래스의 데이터와 메서드를 외부로부터 숨기고, 외부에서 직접적인 접근을 제한하는 개념. 캡슐화는 정보 은닉을 통해 클래스의 내부 구현을 보호하고, 데이터의 무결성과 일관성을 유지하는 데 도움을 준다. 그러나 몇 가지 경우에는 캡슐화가 깨질 수 있다.

1) 접근 지정자의 오용

: 자바에서는 접근 지정자(public, protected, private)를 사용하여 멤버의 접근 범위를 제어한다. 캡슐화가 깨질 수 있는 경우는, 적절하지 않은 접근 지정자를 사용하여 멤버에 직접 접근하는 것이다. 예를 들어, private으로 선언된 멤버에 대해 외부에서 접근하려는 경우 캡슐화가 깨질 수 있습니다.

ex) 클래스 안에 클래스 안에 있는 멤버에 대해서 class.class.kor로 접근한다면 구조를 다 들킨 셈이기 때문에 이건 뭐 거의 해킹이나 같다.

2) Getter와 Setter의 남용

: Getter와 Setter는 클래스의 필드에 접근하는 메서드로, 데이터를 읽고 변경할 수 있는 인터페이스를 제공한다. 그러나 필요 이상으로 많은 필드에 대해 Getter와 Setter를 제공하면 캡슐화가 깨질 수 있다. 모든 필드에 대해 공개적으로 접근할 수 있는 Setter를 제공하면 외부에서 필드 값을 마음대로 변경할 수 있으므로 캡슐화 원칙이 저해된다.

ex) 모든 private 멤버에 대해 getter, setter를 만들 필요는 없으며 밖에서 건드려도 되는 값만 get,set을 제공하여 접근허용하는 의미(권한허용)로 봐야 한다. 밖에서는 허락받은 해당 get,set외에 어떤 것들이 있는지 알 수 없다. 

3) 상속과 재정의(Overriding)

: 상속을 통해 부모 클래스의 멤버를 자식 클래스에서 재사용할 수 있다. 그러나 자식 클래스에서 부모 클래스의 protected 멤버나 메서드를 오버라이딩하면, 자식 클래스 외부에서도 해당 멤버에 접근할 수 있게 되어 캡슐화가 깨질 수 있다.

4) 직렬화(Serialization)

: 자바의 직렬화 기능은 객체를 바이트 스트림으로 변환하여 저장하거나 네트워크를 통해 전송할 수 있게 한다. 직렬화는 객체의 상태를 외부에 노출시킬 수 있으며, 이는 캡슐화 원칙을 위반할 수 있다.

위는 캡슐화 원칙을 제대로 준수하지 않거나 오용하는 경우로, 캡슐화를 지켜야 객체의 내부 구현이 외부에 노출되지 않으며 객체 간의 결합도를 낮추고 유연성과 유지보수성을 향상시킬 수 있다. 캡슐화가 깨지는 경우에는 코드의 안정성과 확장성에 문제가 생길 수 있으므로 주의해야 한다.

 

👉 클래스가 가진 메서드를 사용할 때 :  클래스명.메서드(인스턴스);

👉 인스턴스가 가진 메서드를 사용할 때 : 인스턴스명.메서드(); 

 

객체가 중심이 되면서, 객체를 통해 생성된 인스턴스로 각 속성과 기능을 접근 한다.

 

 

 

✅추상화 (abstraction)

: 프로그램을 만드는 순서 👉 개체를 찾고 - 기능을 찾고 - 기능의 절차 구현 (구조화 포함)

: 복잡한 현실 세계를 단순화하여 핵심적인 특성만을 간추려 표현하는 것 (단순화, 일반화)

즉, 객체들 간의 공통된 특징과 기능을 추출하여 이를 하나의 개념 또는 클래스로 표현하는 과정.

: 추상화는 코드집중화가 아닌 서비스 집중화 (캡슐단위의 공통서비스)

 

시나리오 안에서 역할을 가지고 있거나 움직임을 가지고 있을때 개체.
하늘은 배경으로만 존재하므로 개체로 치지 않는다.
비행기 자동차, 사람, 소 (동물)

종류명/타입명 - 개체
식별할 수 있는 단위/부여된 각각의 이름 - 객체

추상화 시켜서 이름을 부여했다 ▶ 개별 사물이나 개념을 대표하는 일반적인 용어나 기호 사과. 자동차 등

ex1) 'print()'라는 함수는 다양한 종류의 데이터를 출력하는 기능을 추상화하여 제공
ex2) 'Animal'이라는 클래스는 다양한 종류의 동물들을 나타내기 위한 추상화된 개념

👉 개체/ 객체 / 추상화된 이름을 구별할 수 있도록 한다.

 

 

 

✅ 객체의 특성과 속성

: 두 객체의 상태값을 구분하기 위한 속성 필요.
: 속성값이 다 똑같으면 객체 식별 불가. 도플갱어.

: 따라서 객체식별자(해쉬값)가 붙게 되는데 우리가 붙이는게 아니라  jre를 통해서 붙는다.

hcod src x y size direction 컬럼값 = 개체
1 .img 10 20 10 4 속성 = 객체

 

 

 

✅ static 변수와 메서드 ( 인스턴스 변수,메서드와의 차이점)

 전역변수가 static 이라는 이름을 달고 class안으로 들어가게 되면서 구분하기 위해 static을 붙인다.

 즉 클래스 레벨에서 선언되는 변수로, 해당 클래스의 모든 인스턴스들이 공유한다.

 클래스가 로드될 때 생성되며 프로그램 실행중에 유지된다!

 

//기존에는 객체가 아니라 울타리 역할. (Exam)
void main(){
Exam exam = new Exam();
Exam.input(exam);  // function > 클래스(울타리) 안에 있는 함수인 static method를 클래스명 Exam으로 호출한다


//객체지향으로 처리
Exam exam = new Exam();
exam.input(); // method > 인스턴스인 exam 안에 생성된 함수 instance method
//인스턴스로부터 받아서 쓰는 메소드.
}

 

 

#️⃣ 정적 변수/메소드의 특징

✔ 클래스에 속하므로 객체를 생성하지 않아도 사용할 수 있다.

 클래스 이름으로 참조한다.(* 인스턴스 이름으로 접근할 경우 컴파일은 가능하나 다음과 같은 안내가 뜬다 : The static field Exam.aa should be accessed in a static way)

✔ static은 객체를 전달받는게 아니므로 객체를 통해서 호출하면 안된다. 매개변수를 받아야 한다.

 공유되므로 값을 바꾸면 모든 인스턴스에서 해당 값을 사용 가능하다. 그러나 정적 변수의 남용은 전역 변수의 문제와 유사한 문제를 야기할 수 있으므로 적절히 사용하는 것이 중요.

 

public static void main(String[] args) {
    Exam exam = new Exam(); // 인스턴스 생성 없이도 static은 사용 가능

	Exam.input(exam); // 클래스 안에 있는 input메서드 사용 (static)
   
   	Exam.aa=40; // 올바른 static접근방법
    	exam.aa=30; // 잘못된 static 접근방법 The static field Exam.aa should be accessed in a static way

//		exam.input(); //인스턴스 생성 후에 메서드 사용
    	exam.print();
}
    
//===============================================

public class Exam { // 틀만 잡은 것 .클래스 단위가 캡슐
	static int aa; // 정적 변수. exam객체를 생성해도 별도로 존재. 객체 생성과 무관하게 딱 한번만 생성됨
	int kor;
	int eng;
	int math;
	
	public static void input(Exam exam) { // static 함수
		exam.kor=100;
		exam.eng=100;
		exam.math=100;
	}
	
	public void input() { // 인스턴스 함수
		int kor=30; // 지역변수와 인스턴스 변수를 구분할때 this 사용
		this.kor=3; //exam이라는 객체의 this의 kor 방에 넣음 this는 안쓰면서적응하도록 한다.
		// 지역변수는 리턴하기 전까지 나가지못하더라도 this로 구분해줘야 혼동하지 않고 접근할 수 있다
		eng=20;
		math=100;
	}

	public void print() { // 매개변수를 넘겨받지 않아도 exam을 받는다. 매개변수를 넘겨받지 않으니까 예약된 변수가 있지.
		System.out.printf("kor:%d, eng:%d, math%d\n", kor,eng, math);
	}
}

👉 지역변수명과 인스턴스 변수 명을 구분할 때, 인스턴스명을 this로 사용한다. 즉 exam이란 인스턴스의 input()메서드로 작동하므로, this는 exam이란  인스턴스변수명을 가리킨다. (* 평소에는 this를 생략해서 써도 해당 인스턴스의 변수값이다)

 

👉 그러나 지역변수명이 본래 객체의 변수명과 겹칠때는 지역변수를 더 우선으로 인식한다. 즉 메인메서드에서 exam.kor을 호출하면 int kor=30; 이 호출되지, this.kor=3;이 호출되지 않는다. 지역변수가 리턴되지 않은 채로 갇혀있어도 메서드는 지역변수를 우선으로 인식한다! 따라서 인스턴스 변수를 호출할때는 this를 꼭 붙이도록 한다.