(10)-23.10.05[JAVA]

DANA·2023년 10월 4일

KDT-구디아카데미

목록 보기
10/56

mdn mvc - 표준

배열

<예제1>
package com.step4;

public class Array1 {

	public static void main(String[] args) {
		int com[] = new int[3];
		for(int i =0;i<3;i++) {
			System.out.println("com["+i+"] = "+com[i]);
		}
		
		int my[] = {1,2,3};
		// 가진 전부를 처리할 땐 개선된 for문 사용함
		for(int i:my) {
			System.out.print(i);
		}
			System.out.println();
		int other[] = new int[] {1,2,3};
		for(int i:other) {
			System.out.println(i);
		}
	}

}
<예제2>
package com.step4;
// 메소드오버로딩은 같은 이름의 메소드나 생성자를 중복해서 선언할 수 있다
// 단, 이름은 같지만 반드시 파라미터의 개수나 타입은 달라야만 한다
class F {
	F() {
		
	}
	F(int i) {
		
	}
	F(int i, int j) {
		System.out.println(i+","+j); // 출력되었다는 건 내가 호출되었다는 것
	}
	F(boolean isOk) {
		System.out.println(isOk);
	}
	F(String s, int i) {
		
	}
}

public class Fmain {

	public static void main(String[] args) {
		F f = new F(1,2);
		System.out.println(f);
		f = new F(true); // f 앞에 F 안 쓰는 것에 대해 확실한 이해 필요
		// 객체배열, 자료구조, Web or Hybrid - JSON 얘기할 때도 사용함
		System.out.println(f); // 다른 주소번지를 가질 것이다 - 예측하기
	}

}
<예제3-1>
package com.step4;
class GLogic {
	int i = 1;
	
}
public class GView {
	// 빨간 줄 뜨는 이유: 디폴트 생성자만 생략 가능함
	GLogic gi = new GLogic(this); // 여기서 this는 현재 스레드 관리하는 클래스이고, 원본이라 보면 된다(나 자신) 현재 메모리에 로딩돼 있음
	public static void main(String[] args) {

	}

}
<예제3-2>
package com.step4;
class GLogic {
	int i = 1;
	GLogic(GView gv) { // 이때까지는 gv가 null
		System.out.println(gv);
	}
}
public class GView {
	GView(){ 
		GLogic gi = new GLogic(this); 
	}
	public static void main(String[] args) {
		// static 안에서는 this나 super(부모클래스 나타내는 수정자) 사용이 불가하고
		// 이 말은 즉 생성자에서는 가능하다
		GView gv = new GView();
	}

}
<예제 3-3.this 설명+처리순서>
package com.step4;
class GLogic {
	int i = 1;
	GLogic(GView gv) { // 이때까지는 gv가 null // 5 // 11
		System.out.println("GLogic:"+gv); // 6(출력) // 12(출력) // GView gv = new GView(); 여기 gv 주소번지와 같을까?
	}
}
public class GView {
	GView(){ // 3 // 9(또 경유)
		// 2번 경유한다
		GLogic gl = new GLogic(this); // 4 // 10
	}
	public static void main(String[] args) { // 1
		// static 안에서는 this나 super(부모클래스 나타내는 수정자) 사용이 불가하고
		// 이 말은 즉 생성자에서는 가능하다
		// 이때 this는 앞에건가? 아님 뒤에꺼?
		GView gv = new GView(); // 2 // 7  
		gv = new GView(); // 8 
		System.out.println(gv); // 12(출력)
	} 

}
<예제3-4.this 설명>
package com.step4;
class GLogic {
	int i = 1;
	GLogic(GView gv) { // 이때까지는 gv가 null
		System.out.println("GLogic:"+gv); // GView gv = new GView(); 여기 gv 주소번지와 같을까?
		System.out.println("GLogic i:"+gv.j); // GView gv = new GView(); 여기 gv 주소번지와 같을까?
	}
}
public class GView {
	int j = 1;
	GView(){ 
		GLogic gl = new GLogic(this); 
	}
	public static void main(String[] args) { 
		// static 안에서는 this나 super(부모클래스 나타내는 수정자) 사용이 불가하고
		// 이 말은 즉 생성자에서는 가능하다
		// 이때 this는 앞에건가? 아님 뒤에꺼?
		GView gv = new GView(); // 여기 주번과
		gv = new GView(); // 여기 주번이 다르다
		gv.j = 10; // 서로 다른 값을 가질 수 있다 - 이중적이다 - 좋지 않다
		// 이걸 절대 방어하려면 static으로 하든가 아님 싱글톤으로 처리하시오 - 메모리 누수
		System.out.println(gv); 
	} 

}
<예제4-1>
package com.step4;
class Dept {
	// 전변은 초기화를 생략할 수 있다. 왜냐면 생성자가 대신 해주니까
	private int deptno;
	private String dname;
	private String loc;
	Dept(){
		
	}
	Dept(int deptno, String dname, String loc){
		// 현재 메모리에 활성화 되어있는(언제든 사용이 가능한, 준비가 되어있는) 원본의 객체를 참조하고 있다. 누가? this가
		this.deptno = deptno;
		this.dname = dname;
		this.loc = loc;
	}
}
public class DeptMain {

	public static void main(String[] args) {
		// 인스턴스화를 안 된다 - 캡슐레이션(캡슐화): 그 사물을 정의하는 아주 중요한 고유명사. 이런 건 함부로 손대면 안됨
		System.out.println(deptno);

	}

}
<예제4-2>
package com.step4;
// lombok
class Dept {
	// 전변은 초기화를 생략할 수 있다. 왜냐면 생성자가 대신 해주니까
	private int deptno;
	private String dname;
	private String loc;
	Dept(){
		
	}
	Dept(int deptno, String dname, String loc){
		// 현재 메모리에 활성화 되어있는(언제든 사용이 가능한, 준비가 되어있는) 원본의 객체를 참조하고 있다. 누가? this가
		this.deptno = deptno; // 이거 막으면 동기화가 안 되니까 10이 아니라 0이 나옴
		this.dname = dname;
		this.loc = loc;
	}
	public int getDeptno() { // getDeptno는 전변 // gettersetter는 전변 바라보고 있다
		return deptno;
	}
	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}
	public String getDname() {
		return dname;
	}
	public void setDname(String dname) {
		this.dname = dname;
	}
	public String getLoc() {
		return loc;
	}
	public void setLoc(String loc) {
		this.loc = loc;
	}
}
public class DeptMain {
	/*
	 * 왜 10일까? 힌트 한 번 얘기해줘봄
	 * Dept 클래스에 getter와 setter를 두는 건 결국 전역변수를 사용하기 위함이다
	 * 부서관리 - ERP
	 * 업무담당자 - 사원수가 150명이라면, 이 사람들이 시스템 쓰는데 같은 정보 원할까? 아닐걸요 
	 * -> 웹서비스. 웹이 돼야 동기화가 가능하니까. 
	 * 150명 - 인스턴스를 갖는다 - 하나야 - 스레드로 지원함 - 싱글톤 - 영속성을 유지해야 한다면(오라클, Mysql,...), 세션과 쿠키(시간을 지정할 수 있다)
	 * 그 스레드에 그 인스턴스는 지변 성격을 갖는다
	 */

	public static void main(String[] args) {
		// 퍼블릭이면 막 갖다 쓰면 되나? 아니. 인스턴스화 해야지.
		Dept dept = new Dept();
		// 생성자를 활용해서도 캡슐화된 전변을 재정의할 수 있다
		// 이 때 생성자 내부에서는 반드시 전변과 생성자의 파라미터 값을 동기화 해줄 것- 이걸 빠뜨리면 다른 값을 가질테니까
		// dept1 = new Dept(10,"개발1팀","부산"); -> 지금은 이게 아니고
		Dept dept1 = new Dept(10,"개발1팀","부산"); // -> 이렇게 보는 게 나음
		// 인스턴스화를 안 된다 - 캡슐레이션(캡슐화): 그 사물을 정의하는 아주 중요한 고유명사. 이런 건 함부로 손대면 안됨
		System.out.println(dept.getDeptno()); // 0
		// dept1=null; // 캔디데이트 상태 -> 넌 앞으로 쓰레기 값이 될거야-> dept1 = new Dept(); 이거 하면 앞에 new Dept(10,"개발1팀","부산"); 이 객체는 쓸 수 없다. 끊어졌기 때문에
		// dept1.deptno = 0; // 이건 안 됨 
		dept1.setDeptno(100); // 이러면 100 출력 // 이걸 막으면 다시 10나옴 // 원시형 타입 변수 한 번에 하나만 담을 수 있다 // 위에가 dept1=null; 이걸로 되면 이건 NullPointerException
		dept1.setDname("운영1팀");
		dept1.setLoc("제주"); // 이러면 오버라이트인데.
		System.out.println(dept1.getDeptno()); // 10 왜요?
		System.out.println(dept1.getDeptno()+dept1.getDname()+dept1.getLoc());
		System.out.println(dept.getDeptno()+dept.getDname()+dept.getLoc()); // null
	}
}
package com.step4;

public class H {
// 사용자정의 클래스와 자바제공클래스 섞어쓰기
// 관심사가 변경되었다 -> 클래스 나누어서 연습할 것
// 클래스 쪼개기 -> 명분(MVC) -> 자바(스프링) -> 이 스프링이 제어역전(역제어), dependency, injection(DI) -> 스프링 핵심들
// git 공부하자 -> 나누어 개발하기 -> 웹개발 -> 클라이언트 사이드개발, 서버사이드 개발 필요하다
	public static void main(String[] args) {
		String msg = new String("안녕");
		System.out.println(msg);
	}

}
<예제5>
package com.step4;
class J {
	// 선언부
	int a;
	// 왜 에러인가요? - 파라미터를 갖는 생성자는 JVM이 추측 불가함
	Jmain jm = new Jmain(this);
	J(){ // 디폴트 생성자는 파라미터가 없으니까 생략해도 JVM이 제공해줌
		
	}
}
public class Jmain {
	int b;

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
<예제5-2. 디폴트 생성자가 없어요>
package com.step4;
class J {
	// 선언부
	int a;
	// 왜 에러인가요? - 파라미터를 갖는 생성자는 JVM이 추측 불가함
	Jmain jm = new Jmain(this);
	J(){ // 디폴트 생성자는 파라미터가 없으니까 생략해도 JVM이 제공해줌
		
	}
}
public class Jmain {
	int b;
	J j = null;
	Jmain(J j){
	}
	void methodA() {
		// 파라미터로 넘어온 원본을 쓰고 싶다. 어떡하지?
		// 원본이 뭘 의미하나요? - J가 Heap 메모리 영역에 활성화되었을 때 그 주소번지(캔디데이트 되지 않은, 호출했을 때 바로 사용할 수 있는
		System.out.println(j);
	}
	public static void main(String[] args) {
		Jmain jm = new Jmain(); // 디폴트 생성자가 없어요
		jm.methodA();
	}

}
<예제5-3.this.j=j;를 경유하지 않았으니까>
package com.step4;
class J {
	// 선언부
	int a;
	// 왜 에러인가요? - 파라미터를 갖는 생성자는 JVM이 추측 불가함
	Jmain jm = new Jmain(this);
	J(){ // 디폴트 생성자는 파라미터가 없으니까 생략해도 JVM이 제공해줌
		
	}
}
public class Jmain {
	int b;
	J j = null;
	Jmain(){
		
	}
	Jmain(J j){
		this.j=j;
	}
	void methodA() {
		// 파라미터로 넘어온 원본을 쓰고 싶다. 어떡하지?
		// 원본이 뭘 의미하나요? - J가 Heap 메모리 영역에 활성화되었을 때 그 주소번지(캔디데이트 되지 않은, 호출했을 때 바로 사용할 수 있는
		System.out.println(j);
	}
	public static void main(String[] args) {
		Jmain jm = new Jmain(); // 디폴트 생성자가 없어요
		jm.methodA(); // null이 출력될 것이다. 왜냐하면 this.j=j;를 경유하지 않았으니까
	}

}
<예제5-4>
package com.step4;
class J {
	// 선언부
	int a;
	// 왜 에러인가요? - 파라미터를 갖는 생성자는 JVM이 추측 불가함
	Jmain jm = new Jmain(this);
	J(){ // 디폴트 생성자는 파라미터가 없으니까 생략해도 JVM이 제공해줌
		
	}
}
public class Jmain {
	int b;
	J j = null;
	Jmain(){
		
	}
	Jmain(J j){
		this.j=j;
		// b = 10; // 원래 0이었는데 이걸 써줌으로 값이 10으로 변함
		this.b = 10; // 이렇게도 가능
	}
	void methodA() {
		// 파라미터로 넘어온 원본을 쓰고 싶다. 어떡하지?
		// 원본이 뭘 의미하나요? - J가 Heap 메모리 영역에 활성화되었을 때 그 주소번지(캔디데이트 되지 않은, 호출했을 때 바로 사용할 수 있는
		System.out.println(j);
	}
	public static void main(String[] args) {
		J j = new J();
		Jmain jm = new Jmain(j);
		System.out.println(jm.b); // 원래 0인데 b = 10; 이걸 넣음으로서 10 출력
		jm.methodA(); // null이 출력될 것이다. 왜냐하면 this.j=j;를 경유하지 않았으니까
	}

}
<예제5-5>
package com.step4;
class J {
	// 선언부
	int a;
	// 왜 에러인가요? - 파라미터를 갖는 생성자는 JVM이 추측 불가함
	Jmain jm = new Jmain(this);
	J(){ // 디폴트 생성자는 파라미터가 없으니까 생략해도 JVM이 제공해줌
		
	}
}
public class Jmain {
	int b;
	J j = null;
	Jmain(){
		// 텅텅 빈 깡통. 아무런 일도 하고 있지 않다. - 아무런(전변 j, b) 초기화도 하지 않았다
	}
	Jmain(J j){ // 생성자도 파라미터 자리를 갖는다. 이 파라미터 자리에 참조형을 넘길 수 있다
		this.j=j;
		// b = 10; // 원래 0이었는데 이걸 써줌으로 값이 10으로 변함
		this.b = 10; // 이렇게도 가능
	}
	void methodA() {
		// 파라미터로 넘어온 원본을 쓰고 싶다. 어떡하지?
		// 원본이 뭘 의미하나요? - J가 Heap 메모리 영역에 활성화되었을 때 그 주소번지(캔디데이트 되지 않은, 호출했을 때 바로 사용할 수 있는
		System.out.println(j);
	}
	public static void main(String[] args) {
		J j = new J();
		Jmain jm = new Jmain(j);
		jm = new Jmain(); // 이걸 넣으면 어떻게 될까? // 생성자가 두 번 호출되는데 자바에서는 메소드오버로딩컨벤션이라서 같은 이름이더라도 다른 생성자 인식함 
		// 이걸 막으면 주소번지가 출력 됨
		System.out.println(jm.b); // 0이 나옴-디폴트 생성자가 호출되면 0이 출력되고, 파라미터를 가진 생성자가 호출되면 10이 출력된다.
		jm.methodA(); // null이 출력될 것이다. 왜냐하면 this.j=j;를 경유하지 않았으니까
	}

}
<예제6>
package com.step4;
class K {
	K(Kmain km) {
		System.out.println("K===> "+km);
	}
}
public class Kmain {

	public static void main(String[] args) {
		Kmain km = new Kmain();
		km = new Kmain();
		System.out.println("Kmain===> "+km); // 이 위치에 따라 주소번지가 다르게 출력되는 걸 확인해야 한다
		K k = new K(km);
	}

}

주소값이 같을까? 같다면 왜 같을까?


복습

<예제7-클래스 2개>
package com.step4;
// 인스턴스화가 A a = new A(); 인 것 알면 기초는 아는 것
// 역할은? a.전변호출한다 / a.사용자정의메소드 호출한다
class L {
	int i = 1; // 전역변수 선언-외부클래스에서 접근 가능(단 인스턴스화 해야한다)
}
public class Lmain {
	void methodA(L l) { // 메소드 구현은 좌중괄호 우중괄호로 끝남
		System.out.println("호출성공"+l);
		int j = l.i; // 대입연산자를 통해서 오른쪽의 값을 왼쪽에 대입하시오
		System.out.println(j);
	} // end of methoda()
	public static void main(String[] args) { // 1
		// Lmain 클래스에서 L클래스에 정의된 전변 i를 사용하고 싶다면?
		// Lmain 안에서 L클래스가 인스턴스화 되어야 한다.(제어권을 Spring이 가짐 <--스프링이 대신 인스턴스화 해주는 것이다<-객체에 대한 라이프사이클을 관리해준다)
		// 인스턴스화의 여러 방법 꼭 체크해본다
		// 어떤 클래스명으로 인스턴스화를 진행할 건가요?
		L l = new L(); // 지변의 성격이다
		Lmain lm = new Lmain();
		lm.methodA(l); // 메소드 호출은 세미콜론으로 끝난다
	}

}

<예제8>
package com.step4;
class M {
	int tot; // 총점 담기
	double avg; // 평균 담기
}
class M1 {
	void hap(int n1) { // 지역변수는 초기화 안 해줌
		System.out.println("hap(n1)===>"+n1);
		// System.out.println("hap()"+n2); // 지역변수여서
	}
	void hap(M1 m1) {
		System.out.println("hap(M1)===>"+m1);
	}
}
public class Mmain {

	public static void main(String[] args) {
		int n1 = 70;
		int n2 = 80;
		int n3 = 90;
		M1 m1 = null; // M1 m1 = new M1(); 이걸 두 줄로 나눈 건데
		// 여기 공백에서 시점(위치)의 문제가 발생할 수 있음
		// m1.hap(); // null이라서 호출 불가능
		System.out.println(m1); // null 출력 / 여기서 호출하면 NullPointerException
		m1 = new M1();
		System.out.println(m1);
		// m1.hap(M1); 
		m1.hap(m1); 
        // 지변이더라도 파라미터를 통해서 원본을 넘기면 다른 메소드에서도 사용이 가능하다
	}
}
<예제9 증감연산>
package com.step4;

public class Oper2 {

	public static void main(String[] args) {
		int i = 1;
		// 대입이 먼저야 - 1
		
		int j = ++i; // 2, 2 출력 // ++증감연산자 1씩 증가해주세요 - 변수 앞에 있으면 먼저 증가함
		// 증감연산자가 앞에 있으면 먼저 1 증가시키고 대입한다
		System.out.println(i+","+j);
		j = i++; // 2, 1 출력
		System.out.println(i+","+j);
		j = --i;
		// --i=> i = i-1;
		System.out.println(i+","+j);
	}

}
<예제10-1 증감연산>
package com.step4;

public class Oper1 {

	public static void main(String[] args) {
		int i = 1;
		int j = 2;
		if((++i>j)|(i<j--)) { //(2>2 or 2<2)
			System.out.println("참");
		} else {
			System.out.println("거짓");
		}
		System.out.println(i+","+j);
	}

}
<예제10-2 증감연산>
package com.step4;

public class Oper1 {

	public static void main(String[] args) {
		int i = 1;
		int j = 2;
		// 이거나 비교일 때는 첫번째 조건이 참이면 두 번째 조건은 따질 필요가 없다. 왜냐하면 어차피 실행 될 거니까
		// 첫 번째 조건만 따지고도 실행문이 결정된다.
		// 예) 아이디 중복검사 - 
		if((++i>=j)||(i<j--)) { // 2>=2 or 2<2
			System.out.println("참");
		} else {
			System.out.println("거짓");
		}
		System.out.println(i+","+j); // 2,2 출력
	}

}
<예제11 증감연산>
package com.step4;

public class Oper3 {

	public static void main(String[] args) {
		int i = 1; // i=1
		int j = i++; // j=1 / 왜냐면 대입이 먼저니까. 무조건 ++이 뒤에 있으면 나중에 증가시킴
		System.out.println(i+","+j);
		if((i>++j)&(i++==j)) {
			System.out.println("참일 때");
		} else {
			System.out.println("거짓일 때");
		}
		i+=j;
		System.out.println(i+","+j);
	}
}
/*
True & True -> True  &엔퍼센트 연산자
True & False -> False
False & True -> False
False & False -> False
 
&& 두 개이면 &일 때와 똑같은데
처음 조건이 false이면 뒤에 조건이 참이어도 어차피 실행문이 실행되지 않는다
이러한 이유로 && 두 개를 사용하는 거다 - 일량을 줄여준다. (뒤에 있는 조건 따지지 않는다)
한 개든 두 개든 결과에는 영향이 전혀 없다
 
True | True -> True  |파이프 연산자
True | False -> True
False | True -> True
False | False -> False
 */
<예제12 증감연산>
package com.step4;

public class Oper4 {

	public static void main(String[] args) {
		int i = 1;
		int j = 10;
		do {
			System.out.println("if문 이전 - 나는 무조건 실행된다");
			if( i>j ) break; // 1>10? false
			System.out.println("if문 조건을 만족하면 나는 못 본다");
		     j--; //    9    8    7    6...
		     // ++i -> 2<5, 3<5, 4<5, 5<5
		    } while(++i < 5); // while문 조건에 j가 없다 - 중요하지 않다
		System.out.println("요기");
		// 실행후 i , j의 값은? 
		System.out.println(i+","+j);
	}
}
<예제13-1. - i를 쓰지 말고..>
package com.step4;

public class UnitTest {

	public static void main(String[] args) {
		BaseBallGame bbg = new BaseBallGame();
		String hint = null;
		for(int i=0;i<3;i++) {
			hint = bbg.account(i+"회차: "+"25"+ ++i);
			System.out.println(hint);
		}
		
		// for(int i=0;i<10;i++) {
		// bbg.ranCom();
		// System.out.println(bbg.com[0]+""+bbg.com[1]+""+bbg.com[2]);
		// }
	}
}
<예제13-2. 해결>
package com.step4;

public class UnitTest {

	public static void main(String[] args) {
		BaseBallGame bbg = new BaseBallGame();
		String hint = null;
		int cnt = 0;
		for(int i=0;i<3;i++) {
			hint = bbg.account(++cnt + "회차: "+"25"+ ++i);
			System.out.println(hint);
		}
		
		// for(int i=0;i<10;i++) {
		// bbg.ranCom();
		// System.out.println(bbg.com[0]+""+bbg.com[1]+""+bbg.com[2]);
		// }
	}
}
<예제14-1. This>
package com.step4;

import javax.swing.JFrame;

class ZipcodeApp{
	// 선언부
	JFrame jf = new JFrame();
	// 생성자 - 생성자도 메소드처럼 좌중괄호 우중괄호로 영역을 가짐 - 실행문(초기화, for, if 포함)이 올 수 있다
	ZipcodeApp(){
		initDisplay();
		// 메인메소드의 zc.initDisplay();를 여기에 가져올 수 있다. 대신 인스턴스화 필요없음
		// 생성자에서도 메소드호출 가능하다 -> 뭐가 다르지? 같은건가? - 결과, 어떤 상황일 때 차이점 발견한다
		// 선처리와 후처리 필수 파악
		
		// 메소드호출순서를 정할 수 있어야한다(대기상태, 지연, 데드락..)
	}
	// 화면그리기
	public void initDisplay() {
		System.out.println("화면그리기");
		jf.setSize(400, 600);
		jf.setVisible(true);
	}
}
public class ThisMain {
	ThisMain(){
		
	}
	public static void main(String[] args) {
		// initDisplay 호출
		ZipcodeApp zc = new ZipcodeApp();
		// zc.initDisplay();
	}
}
<예제14-2. This>
package com.step4;

import javax.swing.JFrame;

class ZipcodeApp{
	JFrame jf = new JFrame();
	
	ZipcodeApp(ThisMain tm){
		System.out.println(tm.i);
		for(double d=0;d<99999999999999999999999999999.0;d++) {
			System.out.println("커피를 내리는 시늉을 하고 있다"); // 그럼 이 시간동안 지연되는 것(지연, 대기, 순서대로..)
		}
		initDisplay();
	}
	
	public void initDisplay() {
		System.out.println("화면그리기");
		jf.setSize(400, 600);
		jf.setVisible(true);
	}
}
public class ThisMain {
	int i = 1;
	ThisMain(){
		
	}
	public static void main(String[] args) {
		ThisMain tm = new ThisMain();
		ZipcodeApp zc = new ZipcodeApp(tm); // static을 사용하지 않으면서 세 개의 나눠진 클래스가 한 몸처럼 움직이게 한다
	}
}

야구게임화면

BaseBallGame

ranCom(): void - com배열에 0부터 9사이의 채번된 값을 담기
-> BaseBallGameLogic.java

account(String):String - 사용자가 입력한 숫자와 정답을 비교하여 숫자가 존재하면 볼, 자리까지 일치하면 스트라이크를 증가시킴
파라미터는 사용자가 입력한 숫자이고 리턴타입은 힌트문이 출력됨
-> BaseBallGameLogic.java

initDisplay():void - 화면을 그린다(프론트엔드가 하는 일)
-> BaseBallGameView.java

exit():void - 게임 종료하기 구현(종료버튼을 누르거나 컴터 강제 종료하거나 또는 윈도우 창에 X버튼을 누르는 경우)-3가지 경우에 모두 사용되니까 메소드를 설계하였다
-> BaseBallGameEvent.java

actionPerformed(ActionEvent):void - 이벤트 처리시
-> BaseBallGameEvent.java

이거 왜 정리하는 거지?
클래스를 3개로 쪼갤 때 메소드를 적당한 클래스에 배치해야 하니까
-> 도식화하는 이유는 세 개의 클래스에 적절하게 배치해야 하므로 그려본다

3개로 쪼갰을 때 학습목표
1. 클래스 사이의 관계를 정확히 파악하여 필요한 곳에 인스턴스화를 할 수 있다.
2. 인스턴스화의 위치에 따라 NullPointerException이 발생할 수 있다는 걸 설명하고 해결할 수 있다
3. static 대신에 생성자 호출을 통해서 객체주입을 받아내는 코드를 작성할 수 있다

<메인>
package com.step4;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
// BaseBallGameView로 가야 하는 전변이 있고
// BaseBallGameLogic로 가야 하는 전변이 있고
// BaseBallGameEvent로 가야 하는 전변이 있다

import com.week2.BaseBallGameView;

public class BaseBallGame implements ActionListener { // ActionListener: 이벤트 처리 담당하는 메소드
	// 선언부 - 전역변수의 성격을 가진다 (코드적으로 얘기하면 인스턴스변수.변수명으로 어떤 클래스에서든 사용 가능하다)
	JFrame jf = new JFrame();
	//이미지를 담은 물리적인 위치 선언하기.
	String 		imgPath = "D:\\workspace_java\\dev_java\\src\\com\\week2\\";
	//	ImageIcon 	titleIcon = new ImageIcon(imgPath+"yagu.png");
	//ImageIcon 	bg = new ImageIcon(imgPath+"dreamballpark.jpg");
	Image img = null;
	JMenuBar 	jmb 		= new JMenuBar();
	JMenu	 	jm_game 	= new JMenu("게임");
	JMenuItem   jmi_new 	= new JMenuItem("새게임");
	JMenuItem   jmi_dap 	= new JMenuItem("정답");
	JMenuItem   jmi_clear 	= new JMenuItem("지우기");
	JMenuItem   jmi_exit 	= new JMenuItem("나가기");
	JMenu	 	jm_info 	= new JMenu("도움말");
	JMenuItem   jmi_detail 	= new JMenuItem("야구숫자게임이란?");
	JMenuItem   jmi_create 	= new JMenuItem("만든사람들");
	//중앙에 들어갈 속지 선언
	JPanel jp_center = new JPanel();
	//세자리 숫자를 입력 후 엔터를 쳤을때 사용자가 입력한 숫자와 숫자를 맞추기 위한 힌트문
	//을 출력해줄 화면.
	JTextArea jta_display = null;
	JScrollPane jsp_display = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
	JTextField jtf_user   = new JTextField();
	//글꼴과 글꼴에 대한 스타일과 글자 크기를 정해줌.-인스턴스화를 통해서, 그 값들은 생성자의 파라미터로 결정됨
	Font f = new Font("Thoma",Font.BOLD,14);
	//동쪽에 들어갈 속지 생성하기
	JPanel jp_east   = new JPanel();
	//새게임, 정답, 지우기, 나가기 버튼 추가하기
	JButton jbtn_new 	= new JButton("새게임");
	JButton jbtn_dap 	= new JButton("정답");
	JButton jbtn_clear 	= new JButton("지우기");
	JButton jbtn_exit 	= new JButton("나가기");
	int my[]  = new int[3];
	int com[] = new int[3]; // 세 자리 임의의 숫자를 담을 1차 배열 선언 - BaseballGameLogic으로 보내야 하는지? 아님 BaseballGameEvent에 있어야 하는지
	int cnt = 0;//++cnt 힌트 문장에서 순번을 출력하는 변수 - 야구 회차를 나타내는 전역변수. 왜? 그 게임이 유지되는 동안에는 변해야 한다
	// 새 게임이 시작(새 게임을 알리는 메소드가 호출됨- 새 게임일 때 초기화 해야하는 변수가 반드시 존재함)되면 다시 0으로 초기화 해야 한다
	
	// 생성자
	
	// 사용자정의 메소드
	// 세 자리 임의의 숫자를 채번하는 메소드 구현하기
	// 중복을 제거하여 채번한 숫자를 1차 배열에 초기화하기 
	public void ranCom() { // 새게임 버튼이 눌리면 호출되고 또 최초 실행하자마자 바로 호출될 수도 있다
		Random r = new Random();
		com[0] = r.nextInt(10);
		// do..while()문 조건검사를 나중에 하므로 무조건 한 번은 실행되고, while문은 먼저 조건 검사를 하니까 한 번도 실행이 안 될 수 있다
		do {
			com[1]=r.nextInt(10);
		} while(com[0]==com[1]);
		do {
			com[2]=r.nextInt(10);
		} while(com[0]==com[2]||com[1]==com[2]); 
	}
	//사용자가 입력한 값을 판정하는 메소드를 구현해 봅시다.
	public String account(String user) {
		if(user.length()!=3) {
			return "세자리 숫자를 입력하세요.";
		}
		//사용자가 jtf_user에 입력한 숫자는 보기에는 숫자 처럼 보여도 알맹이는 문자열로 
		//인식을 합니다. 그래서 형전환을 한 후 my[]배열에 담아야 함니다.
		//문자열 "256"을 숫자로 담을 변수 선언
		int temp 	= 0;
		int strike 	= 0;//힌트로 사용될 스트라이크를 담을 변수 선언
		int ball 	= 0;//볼을 담을 변수 선언
		//strike와ball을 지역변수로 해야 하는건 매 회차 마다 값이 변해야 하기 때문이다.
		try {
			temp = Integer.parseInt(user);
		} catch (NumberFormatException e) {
			return "숫자만 입력하세요.";
		}
		return strike+"스  "+ball+"볼";
	}
	
	//나가기 버튼이나 나가기 메뉴 아이템을 선택(클릭)했을때 호출되는 메소드 구현
	public void exit() {

	}
	
	// 여기에 화면을 그리는 메소드 입양
	//화면을 그려주는 메소드 선언
	public void initDisplay() {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
		jta_display = new JTextArea();
		jsp_display = new JScrollPane(jta_display);
		jta_display.setOpaque(false);
		jf.setResizable(false);
		//jf.setContentPane(new BgPanel());
		//////////////// 툴바에 들어갈 이미지 버튼 추가하기 ///////////////
		//////////////// 메뉴 바 추가 시작 /////////////////
		jm_game.add(jmi_new);
		jm_game.add(jmi_dap);
		jm_game.add(jmi_clear);
		jm_game.add(jmi_exit);
		jm_info.add(jmi_detail);
		jm_info.add(jmi_create);
		jmb.add(jm_game);
		jmb.add(jm_info);
		//////////////// 메뉴 바 추가  끝   /////////////////
		System.out.println("initDisplay 호출 성공");
		//이벤트 소스와 이벤트 처리 클래스를 매핑하는 코드 추가
		//EventHandler ehandler = new EventHandler();
		//jtf_user.addActionListener(ehandler);//여기서 this는 자기자신 클래스를 가리킴.-BaseBallGame:내안에 actionPerformed
		jtf_user.addActionListener(this);//여기서 this는 자기자신 클래스를 가리킴.-BaseBallGame:내안에 actionPerformed
		jbtn_new.addActionListener(this);
		jbtn_dap.addActionListener(this);
		jbtn_clear.addActionListener(this);
		jbtn_exit.addActionListener(this);
		jmi_exit.addActionListener(this);
		jbtn_new.setBackground(new Color(158,9,9));
		jbtn_new.setForeground(new Color(212,212,212));
		jbtn_dap.setBackground(new Color(7,84,170));
		jbtn_dap.setForeground(new Color(212,212,212));
		jbtn_clear.setBackground(new Color(19,99,57));
		jbtn_clear.setForeground(new Color(212,212,212));
		jbtn_exit.setBackground(new Color(54,54,54));
		jbtn_exit.setForeground(new Color(212,212,212));
		jp_east.setLayout(new GridLayout(4,1));
		jp_east.add(jbtn_new);
		jp_east.add(jbtn_dap);
		jp_east.add(jbtn_clear);
		jp_east.add(jbtn_exit);
		jta_display.setFont(f);
		jta_display.setBackground(new Color(255,255,200));
		jta_display.setForeground(new Color(57,109,165));

		jf.setJMenuBar(jmb);
		jtf_user.setBackground(new Color(255,255,200));
		jp_center.setBackground(Color.green);
		jp_east.setBackground(Color.black);
		jp_center.setLayout(new BorderLayout(0,10));
		jp_center.add("Center",jsp_display);
		jp_center.add("South",jtf_user);
		jta_display.setLineWrap(true);
		jf.setLayout(new BorderLayout(10,20));
		jf.add("Center",jp_center);
		jf.add("East",jp_east);
		jf.setTitle("야구 숫자 게임 Ver1.0");
		jf.setSize(400, 300);
		jf.setVisible(true);
	}
	
	// @는 annotation이라고 읽는다
	// 부모가 정의한 메소드를 재정의하는 것-실제 그 장치에 필요한 기능을 구현하시오
	// 부모(추상클래스-여기서 추상은 '결정되지 않음' 의미)가 정의할 수 없으니(서로 다른 장치라서)
	// 나를 구현하는 클래스마다 그 기능에 차이가 있을테니 그 클래스에서 오버라이딩 하시오
	// 단, 부모의 메소드를 훼손해서는 안됨
	// actionPerformed도 개발자가 직접 호출하는 메소드가 아니다
	// 그럼 언제 누가 왜 호출하는 걸까요? - 콜백함수(javascript에서 쓰는 용어), 콜백메소드(java에서 쓰는 용어)
	// 누가? JVM이
	// 언제? 버튼을 눌렀을 때 혹은 JTextField에서 엔터를 쳤을 때를 JVM이 감지(하드웨어-키보드-입력장치)해 내고
	// 그 때 인터셉트(끼어들어서)해서 필요한 처리를 개발자가 해낸다 = dependency injection(스프링 프레임워크)
	
 	@Override
	public void actionPerformed(ActionEvent e) { // 파라미터 자리에 ActionEvent 객체는 JVM에서 이벤트가 감지되었을 때 대신 주입해줌
		System.out.println("actionPerformed 호출 성공");
		String label = e.getActionCommand();
		System.out.println("너가 누른 버튼의 문자열은 "+label+ " 입니다.");
		Object obj = e.getSource();//이벤트소스의 주소번지를담아줌.
		String input = jtf_user.getText();
		System.out.println(input);
		//너 나가기 버튼이니?
		if("나가기".equals(label)) {

		}
		//새게임을 누른거야?
		else if(obj == jbtn_new) {
			jtf_user.requestFocus();
		}
		//이벤트가 발생한 이벤트 소스의 문자열을 비교하기
		else if(e.getSource()==jtf_user) {
			// 엔터 이벤트가 적용되었을 때 후처리로 JTextField에 문자열을 빈문자열로 교체함
			// JTextArea가 선언부에서는 null이었지만 화면을 그리는 initDisplay()에서 인스턴스화를(생성) 마쳤으므로
			// NullPointerException이 발생하지 않았다 - UI 통해서 테스트 할 때 관전포인트
			// jta_display.setText("문자열");
			// 숫자를 입력하고 엔터를 쳤을 때 JVM이 actionPerformed를 호출하는 거니까 내부에서 출력해볼 수 있다
			// System.out.println(jtf_user.getText());
			System.out.println("엔터쳤을 때: "+jtf_user.getText());
			// 재사용성을 위해서 메소드 호출할 수 있도록 연습 - 메소드로 이관했을 때 동일한 효과
			// cnt = cnt + 1;
			jta_display.append(++cnt+"회: "+jtf_user.getText()+"\n");
			jtf_user.setText("");
		}///////////입력하고 엔터 쳤을 때
		else if(obj==jbtn_dap) {

		}
	} // end of actionPerformed
	
	// 메인메소드 - 최소한의 코드만 작성하도록 연습할 것
	public static void main(String[] args) {
		BaseBallGame bbGame = new BaseBallGame();
		bbGame.initDisplay();
	}
}
<유닛테스트>
package com.step4;

public class UnitTest {

	public static void main(String[] args) {
		BaseBallGame bbg = new BaseBallGame();
		for(int i=0;i<10;i++) {
			bbg.ranCom();
			System.out.println(bbg.com[0]+""+bbg.com[1]+""+bbg.com[2]);
		}
	}
}

0개의 댓글