🔥 Vamos/Java

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

unikue 2023. 4. 6. 18:08

[1] 캡슐화 = 객체지향의 초석. 데이터 구조와 함수를 하나의 영역에 함께 정의하는 것이 목표.

: 프로그램 = 절차

▶ 함수 개체가 많아지는 문제로 수납법 모색

▶ 수납 공간 = 클래스파일

▶ 기능이 아닌 데이터 위주로 수납 (함수의 독립성을 위함)

▶ 구조화된 객체를 사용하는 함수는 객체 구조변경에 취약

ㄴ 클래스 내부가 변경되면 나는 가만히 있어도 영향을 받음

▶ 그 구조에 해당하는 코드 (메서드, 변수 등)들을 모두 같은 클래스 내로 편입

▶ 데이터 구조에 따른 코드 수정 범위를 캡슐 내로 한정 가능하게 됨

 

[2] 함수를 캡슐화 하는 법 = 데이터 구조에 영향을 받는 함수를 한 곳에 모아보자

: 만약 클래스 내에서 변경했는데 다른 곳에 오류가 난다면 캡슐이 깨진 것

public static void main(String[] args){
	ExamList list = new ExamList();
	ExamList.init(list); // 매개변수의 초기화를  해당 클래스에서 진행해달라
}

-------------------------

public class ExamList{
	private Exam[] exams;
	private int current;
	
    public static void init(ExamList list){ // 초기화 진행. 원래는 메인메서드 아래 있던 초기화 값들이 옮겨옴
    list.exams = new Exam[3];
    list.current = 0;
    }
}

 

[3] 인스턴스 메소드
main()에서
ExamList list= new ExamList(); 일때, 

 

ExamList.inputList(list); 로 파라미터를 전달 받는 방식보다 ▶ list.inputList();로 list야.입력해() 메서드 호출이 가독성이 좋음. 

: 인스턴스에 의해 호출되면 인스턴스 값도 자동으로 넘겨받음. 책임도 list가 주체가 되어서 다 지는게 됨(주체)
: 객체지향 = 객체에게 일을 시키는 프로그래밍


[4] 인스턴스 메소드 구현과 static 메소드와의 차이점

class ExamList{
	public static void inputList(ExamList list){
    	list.exams[list.current] = new Exam();
    }
}
//static이 붙은 메서드는 함수 - 모든 메서드는 파라미터를 받게 되어있음

public void inputList(){
	this.exams[this.current] = new Exam();
}
//static이 없는 메서드는 인스턴스 메서드 - 파라미터가 없는데 list라는 인스턴스 값을 받아야 하므로 this예약어를 사용.

① 변경될 메서드에서 static을 지운다

② 매개변수를 지운다 // void inputList(){} 와 같은 형태가 됨

③ 객체 값을 받아서 작동되는 부분들을 this로 변경해준다.


this는 기존에 생성되었던 객체 이름을 대체한다고 생각하면 됨. 헷갈리면 원래 이름으로 치환해서 생각해 볼 것.
this는 생략가능한 경우도 있음


[5] 캡슐화의 은닉성
캡슐: 구조화된 데이터를 모아놓은 집합체. 오류범위가 안쪽으로 한정된다.
캡슐을 깨지 못하게 하는 도구 : 접근 제어 지시자 (private, protected, public)

 

[6] 생성자 = 초기화를 위한 특별한 함수
6-1) 생성자 조건
① 객체가 생성되자마자 무조건! 제일 먼저 실행!
② 생성될때 단 한번만!실행!
* 함수는 언제든지 호출할 수 있도록 이름을 갖고 있지만 생성자는 그렇지 않기 때문에 명시적으로 호출 불가. 함수와는 차이가 있다.

new ExamList+ (); // 새 객체 + (괄호는 초기화하는 생성자를 호출한다는 뜻);

class ExamList{
	public ExamList(){// 생성자는 함수명이 없다. 정의할 때의 함수명은 초기화 할 객체를 한정하기 위한 정식 명칭임 (한정사!)
	exams = new Exam[3];
	current=0;
	}
} // class ends


[7] 생성자 오버로드
: 생성자도 함수의 특징을 갖고 있으므로 오버로드 가능
new ExamList(); // 기본 생성자
new ExamList(10); // 원하는 개수만큼 받아서 초기화하는 생성자

* 생성자 오버로드시 주의사항
1. 기본생성자가 있어야 오버로드도 가능하다
2. 오버로드시 코드의 중복은 재호출을 통해 해결할 수 있어야 한다. this()로 객체를 생성하여 호출.
3. 컴파일러는 생성자가 하나도 없을때만 자동생성해준다. 오버로드생성자 만들때 기본생성자 꼭 추가하기

[8] getters/setters
: 값을 받고 넣는것에 대한 캡슐화
: 데이터 구조가 변경되는 문제에서 독립적이기 위함

[9] 캡슐화 완성

public Exam() { // 오버로드 생성자 작성시 기본생성자도 추가해주기
	this(0,0,0);
}

public Exam(int kor, int eng, int math) {
	this.kor = kor; // 지역변수 값이 인스턴스변수 값과 같으므로 this로 구분해줌 exam.kor=kor;
	this.eng = eng;
	this.math = math;
}


[10] UI코드는 분리하는게 기본
input(): 사용자로부터 입력 받은 / 성적을 목록에 추가하는 함수 ▶  input() , add()로 나눈다
print(): 목록에서 성적을 꺼내서 / 사용자에게 출력하는 함수 get(), print()로 나눈다

class Program{ class ExamConsole{ class ExamList{ class Exam{
main() 메인메서드 소유 각 입출력 콘솔과
연계 담당
ExamConsole에서 필요한
캡슐 여러개 소유
기본적인 속성만 소유
- 사용자가 보는 메인메뉴만 구현됨 (번호를 누르세요)

ExamConsole(); 객체생성

}
printList() - 값 출력
inputList() - 값 입력
}
Exam[] exams;
int current;

get() - 데이터목록에서 배열값 꺼내서 printList()와 연결됨

add() - 배열값 확인하여 가변배열 처리 & 값정리

생성자 - ExamConsole객체부터 연결되어
내려온 초기화 생성자


size() - ExamConsole에서 필요로 하는 current 데이터 연결

}
int kor;
int eng;
int math;


getters - console과 연결
setters
  구성관계: ExamConsole - ExamList - Exam
사용관계: ExamConsole - Exam이 값을 주고받음

사용관계와 구성(도식)관계가 일치하도록 만들기 = has a 상속


[11] has a 상속 = 부품으로 가진다
: 캡슐들은 서로를 사용하거나 사용되는 관계를 가지고 있다

Composition Has A - 콘솔이 필요로하는 객체를 한번에 다 받는것. 10개면 10개 다 마련하고 사용. 포함관계

: A클래스는 B클래스를 Composition has a 방식으로 사용하고있다. = 객체가 만들어질때 A안에서 B가 만들어짐. 일체형


Aggregation Has A - 수시로 모집해서 집합적으로 가진다. 그때그때 마련해서 사용

: ExamList()-Exam()은 그때그때 필요할때 만들어서 사용한다. 누적용 


함수 내에서 사용하는 객체는 ---> dependency (의존객체, 부품)

: Program은 ExamConsole에 의존성을 갖는다.

[12] 코드 재사용이란?
소스코드 > 컴파일 > 배포코드
재사용: 배포된 코드를 사용하는것이 재사용. 소스코드가 아님.

12-1) 제품 배포시
① 컴파일 > Exam.class
② 압축 > Exam.zip
③ 파일명을 jar로 만듦. Exam.jar
이렇게 하면 재사용 가능

12-2) 이클립스에서 배포파일 만들기
: 프로젝트 우클릭  > export > java > jar file - 똑같이 압축하지만 컴파일까지 해서 압축해줌
(*general > archive file  - 기존 프로젝트 중 자바파일을 압축해서 배포할때. 소스코드 배포.)

12-3) 가져다쓸때

: 해당프로젝트 - build path - configure build path - java build path- libraries - add external jars

import part3.ex4.ui코드분리하기.Exam;

public class Program {
	public static void main(String[] args) {
		Exam exam = new Exam(1,1,1);
		
		System.out.println(exam.total()); // 소스코드를 가져오지않고 exam class에 구현된대로 처리됨
	}
}

 


* 오류 처리하기
12-3을 진행하면서 문제가 생겼는데, Exam()객체에 마우스를 올려놔도 import관련 문이 하나도 뜨질않음. Reference Library에 jar파일은 맞게 떠있었음. 뭐가 연동이 안됐나 싶어서 찾기 시작.

영상 댓글을 읽어보니 사람들이 관련 에러 처리한 내역이 있었음

import 까지 하고 total print 시 java.lang.module.FindException: Error reading module: ~~~(파일 경로입니다) Caused by: java.lang.module.InvalidModuleDescriptorException: Program.class found in top-level directory (unnamed package not allowed in module) 라는 오류가 발생해서 modulePath와 classPath 어떤곳에 넣어도 똑같은 오류가 발생했는데 default package가 아닌 새로운 패키지를 만들고 하니 해결되었습니다.


java.lang.NoClassDefFoundError 오류가 뜹니다. 모듈패스가 아닌 클래스패스에 넣으니 실행됩니다.

 

그래서 나도 해봤는데...

1. 패키지 새로 생성하고 모듈이 아닌 클래스에 추가해도 변동없음
2. 이클립스 껐다 켜도 변동없음
3. 삭제 후 재 추가해도 변동없음
4. 다시 export해서 새 파일을 해도 변동없음

 

뭐지...?  싶다가 그냥 단축키 (ctrl+shift+o) 로 import문 넣으니까 해결이 됐다. 뭐니 너...?