Java 객체지향
21. 메소드 동적 바인딩
함수 호출 위치 결정 방식 이해하기
호출되는 함수의 위치 결정 문제
public static void print(Exam exam){
int total = exam.total();
}일때 어떤 total을 불러오냐? 객체전달에 따라서 달라진다.
참조형식에 의한 결정 : 정적 바인딩 컴파일 시점에 결정되어있다.
자바는 실행중에 결정이되고 동적 바인딩이라고 한다.
jump할 위치를 정하지 않음. 자바는 클래스가 2개가 잇으면 메소드의 목록을 테이블로 준비해둔다.
각자 번지를 가지고 있다. 객체 전달시점에 어느 번지로 갈지 결정된다.
객체가 어떤 함수 테이블을 가져갈건지 가지고 간다.
자기 함수테이블에 대한 객체 번지를 추가로 가지고 간다.
따라서 객체에 따라 달라지는 이유는 객체가 알아서 가지고 가기 때문에 달라진다.
22. 코드 집중화와 추상화
객체지향 방법론에서 끝에 있는 것이다. 캡슐들을 사용하는 방법 등을 배웟다.
22.1 코드 집중화
프로그램을 만들때 a프로그램에서 사용하는 일부 b프로그램에서 사용하는 일부가 다 똑같다면?
집중화해서 모아놓고 사용하는게 좋다.호출하는 관계로 사용해야한다.
재사용이아니라 집중화이다. 같은 제품안에서 집중화 하는 것을 의미
처음만들때는 복붙하고 집중화 추상화 캡슐화 등을 한다.
22.2 추상화
코드 집중화 x -> 서비스 집중화(캡슐단위의 공통서비스)
캡슐단위의 집중화를 의미한다. 공통역할을 가지고 있기 때문임.
공통단위를 모아놓고 is a 상속을 하면 구현할필요가 없어진다.
이런 공통화된 클래스, 공통분모화된 클래스를 '추상클래스'라고 한다.
장점
1.코드집중화
2.일괄처리
일괄적으로 담으려한다면? 한번에 담을 수있는 자료형이 없어서 각각 마련해야함
하지만 추상화되면 추상클래스가 부모이기때문에 하나로 참조시킬 수가 있다.
추상클래스로 만드는 두가지 상황 #2
성적관리라고 햇을때? 계속 추가하는데 공통분모가 있으니 만들기 쉽다.
공통분모를 추상클래스라고 한다. 추상클래스가 진짜 추상이되려면 추상클래스만 되어야하고 이게 추상화이다.
23. 추상 클래스 만들기 추상화
Exam클래스를 추상화 할 것이다.
추상화는 공통분모화라고 할수있고 추상클래스는 공통클래스라고 할 수 있다.
역할에 대한 집중화라고 할 수 있다.
완전하게 공통분모로만 사용이 되느냐? 하나로만 만들면되냐 확장해서 사용할수잇느냐?
만들기 위한 공통분모로만 뼈대로만 사용한다면 추상화를 해야한다. 실체화 되지 않도록 해야한다.
Exam이 뼈대로만 사용할 수 있도록 total()/ avg()등을 빼야한다.
new Exam()을 불가능하게 하기 클래스에 abstract를 붙이면된다.
이러면 직접 생성을 할수 없게 된다.
24. 추상 메소드(Abstract Method)
그림판 프로그램을 만든다고 해보자
각 도형마다 기능을 나누어잇다면 각 도형마다 배열을 따로 만들어야한다.
추상화를 하면 하나의 배열로 다받을 수잇다. 공통된 부분을 모으면 집중화 할 수있다.
그런데 paint()의 경우 각자 구현방식이 달라서 오류가 난다.
그래서 shape에 서비스의 정의만 가지게 하면된다.
이것이 뼈대메소드 즉 추상 메소드가 된다.
각자 override하면 실제 객체를 부를때 알아서 사용하게 된다.
추상클래스용도는 두가지이다.
1.공통분모 자료형만들때
2.공통분모로서 다음 버전을 위한 재사용 용도
Exam은 재사용으로 사용할 것임.
추상화 메소드란? 공통으로 제공되어야할 서비스이다.
ExamConsle이 호출할대 실제 호출하는 것은 구현된 객체들이다.
25. 추상 메소드(Abstract Method) 구현하기
추상화를 위한 과제 앞으로 확장될 부분을 확인하고 자식에게 위임하기
뼈대로 만들기2
공통기능인데 내가 구현할 수 없은 상황 -> 그것을자식이 책임지도록 만든다.
abstract method
public abstract class Exam {
int kor;
int eng;
int math;
public Exam() {
this(0,0,0);
}
public Exam(int kor, int eng, int math) {
this.kor = kor;
this.eng = eng;
this.math = math;
}
public int getKor() {
return kor;
}
...
public abstract int total();
public abstract float avg();
}public class NewlecExam extends Exam {
private int com;
public NewlecExam() {
this(0, 0, 0, 0);
}
public NewlecExam(int kor, int eng, int math, int com) {
super(kor, eng, math);
this.com = com;
}
public int getCom() {s
return com;
}
public void setCom(int com) {
this.com = com;
}
@Override
public int total() {
int total = getKor() + getEng() + getMath() + com;
return total;
}
@Override
public float avg() {
return total() / 4.0f;
}
}super.total()로써먹을 수 있엇는데 불편하다. 그래서 exam에 구현하고 구현?
이것은 불가능하다.
protected int onTotal() {
return kor + eng + math;
}@Override
public int total() {
int total = onTotal() + com;
return total;
}불편하다면 자식에게만 공개하는 메소드를 만들어서 사용할수도 있다.
추상클래스가 가지고 있는 공통서비스이다. 목록이 공통이지 구현이 공통인 것은 아님.
26. 팩토리 메소드(Factory Method)
지난시간에배운 추상메소드가 생각보다 많이 쓰인다. 자체보단 패턴으로 쓰인다.
추상화를 한다는 것은 공통화작업을 하는것이다.
공통이아닌데 공통으로 올려둔 이유는 공통 자료형이라는 것이다.
일괄 서비스에 들어가는게 분명하다면 들어가는게 맞아서 구현을 했다.
또다른 클래스 ExamConsole에서 Exam의 기능을 사용하고 있다.
Exam을 공통분모화했기 때문에 오류가 난다. 그대로 사용할 수없다.
그래서 다른 형태의 클래스로 생성해야한다. 재사용하려면 newlec을 만드는 곳에서 소스코드를 가져와서 만들기
소스코드를 만드는게 아니라 binary를 만들어서 교체하는 방법을 찾기
소스코드없이 재사용하는게 가장 알맞다.
이것을 매번 쓰는 패턴이라고 디자인패턴이다. 어떻게 바꿔치기 할것인가?
부모를 추상으로 만들고 객체 생성하는 부분을 자식이 책임질수잇도록만드는것이 팩토리 메소드이다.
이런형태의 패턴을 썻는데 인터페이스 사용하면 굳이 이럴 필요가 없긴하다.
27. 팩토리 메소드 구현하기
public abstract class ExamConsole {
Exam exam = makeExam();
exam.setKor(kor);
exam.setEng(eng);
exam.setMath(math);
}
protected abstract Exam makeExam();public class NewlecExamConsole extends ExamConsole {
@Override
protected Exam makeExam() {
return new NewlecExam();
}
}28. 이벤트 메소드 구현하기
실제 사용하려하면 ExamConsole의 input이 불러들어와서 컴퓨터과목을 입력하지 못하는 문제가 발생한다.
그래서 NewlecExamConsole에서 재정의하려고한다. 그런데 전체 다 작성해서 재정의하면? 나눈이유가없다.
확장될 성적을 입력하는 것을 곰니하면된다.
부모에 추상메소드를 만들고 자식이 구현한 후 부모에서 메소드를 꽃아넣으면된다.
public class Program {
public static void main(String[] args) {
ExamConsole console = new NewlecExamConsole();
console.input();
console.print();
}
}package ch03객체지향.sec05추상화;
import java.util.Scanner;
public abstract class ExamConsole {
// Composiotion Has A 일체형
private ExamList list;
public ExamConsole() {
list = new ExamList();
}
public void print() {
print(list.size());
}
public void print(int size) {
System.out.println("┌──────────────────────────┐");
System.out.println("│ 성적출력 │");
System.out.println("└──────────────────────────┘");
System.out.println();
for (int i = 0; i < size; i++) {
Exam exam = list.get(i);//
int kor = exam.getKor();// exam.kor;
int eng = exam.getEng();// exam.eng;
int math = exam.getMath();// exam.math;
int total = exam.total();// kor + eng + math;
float avg = exam.avg(); // total / 3.0f;
System.out.printf("국어: %3d\n", kor);
System.out.printf("영어: %3d\n", eng);
System.out.printf("수학: %3d\n", math);
onPrint(exam);
System.out.printf("총점 : %3d\n", total);
System.out.printf("평균 : %6.2f\n", avg);
System.out.println("────────────────────────");
}
}
public void input() {
Scanner sc = new Scanner(System.in);
System.out.println("┌──────────────────────────┐");
System.out.println("│ 성적입력 │");
System.out.println("└──────────────────────────┘");
System.out.println();
int kor, eng, math;
do {
System.out.printf("국어: ");
kor = sc.nextInt();
if (kor < 0 || 100 < kor) {
System.out.println("국어성적은 0~100까지의 범위만 입력이 가능합니다.");
}
} while (kor < 0 || 100 < kor);
do {
System.out.printf("영어: ");
eng = sc.nextInt();
if (eng < 0 || 100 < eng) {
System.out.println("영어성적은 0~100까지의 범위만 입력이 가능합니다.");
}
} while (eng < 0 || 100 < eng);
do {
System.out.printf("수학: ");
math = sc.nextInt();
if (math < 0 || 100 < math) {
System.out.println("수학성적은 0~100까지의 범위만 입력이 가능합니다.");
}
} while (math < 0 || 100 < math);
/*
* Exam exam = new Exam(); exam.setKor(kor);//exam.kor = kor;
* exam.setEng(eng);//exam.eng = eng; exam.setMath(math);//exam.math = math;
*/
// Exam exam = new Exam(kor, eng, math);
Exam exam = makeExam();
exam.setKor(kor);
exam.setEng(eng);
exam.setMath(math);
onInput(exam);
// ----------------------add-------------------------
list.add(exam);
System.out.println("────────────────────────");
}
protected abstract void onInput(Exam exam);
protected abstract Exam makeExam();
protected abstract void onPrint(Exam exam);
}public class NewlecExamConsole extends ExamConsole {
@Override
protected Exam makeExam() {
return new NewlecExam();
}
@Override
protected void onInput(Exam exam) {
NewlecExam newlecExam = (NewlecExam) exam;
Scanner sc = new Scanner(System.in);
int com;
do {
System.out.printf("컴퓨터: ");
com = sc.nextInt();
if (com < 0 || 100 < com) {
System.out.println("컴퓨터성적은 0~100까지의 범위만 입력이 가능합니다.");
}
} while (com < 0 || 100 < com);
newlecExam.setCom(com);
}
@Override
protected void onPrint(Exam exam) {
NewlecExam newlecExam = (NewlecExam) exam;
int com = newlecExam.getCom();
System.out.printf("컴퓨터: %3d\n", com);
}
}2023.02.14 후기
추상클래스를 본격적으로 사용하는 파트이다. 책으로 공부할땐 이런게 있구나하고 넘어갔었고 실제 웹앱을 만들때는 인터페이스를 이용하는 일이 많았는데 매우 복잡한 일이라고 느껴진다. 내가 소스코드를 수정할 수 없을때를 가정하고 만들기때문에 디자인하는것이 어려워지는 것이다.
나중에 사용할일이 있을 것 같다.
오늘은 사실 공부가 안되서 조금만 하게 되었다. 평소 얼마나 공부한다고 그런가 싶지만 알 수없는 일 같다.
'기초단계 > JAVA' 카테고리의 다른 글
| 2023.02.15-2 Java 복습 (0) | 2023.02.15 |
|---|---|
| 2023.02.15-1 Java 복습 (0) | 2023.02.15 |
| 2023.02.13 Java 복습 (0) | 2023.02.13 |
| 2023.02.12 Java 복습 (0) | 2023.02.13 |
| 2023.02.11 Java 복습 (0) | 2023.02.12 |