반복 횟수 고정 - While
반복 횟수를 알고 있을 때 다음과 같은 반복구조를 나타낸다.
가장 흔한 반복구조
int n = GOAL_VALUE;
int count = 0;
while (count < n) {
// 코드
count += 1;
}
반복 횟수 사전 예측 불가
반복 횟수를 알고 있지 않을 때 다음과 같은 반복구조를 나타낸다.
사용자의 입력에 따른 반복을 할 때 흔히 쓰는 반복구조이다.
boolean processing = true;
while (processing) {
// 입력
if (/* 종료 신호 수신 */)
processing = false;
else {
// 코드
}
}
# 반복 횟수 사전 예측 불가 - 예시코드
시험 점수 평균을 구해주는 코드이다.
다음은 사용자의 입력을 받고, 사용자가 원할 때까지 입력을 받는다.
사용자의 입력한 사항에 따라 실행을 하므로,
반복에 대한 "예외처리"가 필수사항이다.
예외처리는 경험을 기반으로 설정한다...
import javax.swing.*;
public class CourseManagement {
public double calculateAverage() {
double sum = 0.0;
int count = 0;
boolean processing = true;
while (processing) {
// loop invariant : sum == count개 점수의 합
String message = "다음 시험 점수? (입력 완료시 Cancel 버튼 누름)";
String input = JOptionPane.showInputDialog(message);
if (input == null) // Cancel 버튼을 눌렀음
processing = false;
else {
int score = Integer.parseInt(input);
sum += score;
count += 1;
}
}
if (count == 0) return 0;
else return sum / count;
}
public static void main(String[] args) {
CourseManagement course_mgmt = new CourseManagement();
String message = "평균 점수 = " + course_mgmt.calculateAverage();
JOptionPane.showMessageDialog(null, message);
}
}
검색 결과에 따라 반복
데이터에서 원하는 값을 찾을 때까지 반복을 실행할 때 아래와 같은 코드를 작성한다.
검색 결과에 따른 반복을 진행하므로,
검색할 데이터를 찾았을 때 반복을 종료하는 것과, 검색할 모든 범위의 데이터를 모두 조사했을 때
반복을 종료시킨다.
int index = 0;
boolean found = false;
while (!found && index < s.length()) {
if (s.charAt(index) == c)
found = true;
else
index += 1;
}
# 검색 결과에 따라 반복 - 문자열 검색 예외코드
public class TextSearch {
public int findChar(char c, String s) {
boolean found = false;
int index = 0;
while (!found && index < s.length()) {
// loop invariant:
// (1) found == false : s[0], .., s[index-1]은 모두 c가 아님
// (2) found == true : s.charAt(index) == c
if (s.charAt(index) == c)
found = true;
else
index = index + 1;
}
if (!found)
index = -1;
return index;
}
public static void main(String[] args) {
TextSearch text_search = new TextSearch();
System.out.println(text_search.findChar('a', "Hanyang"));
System.out.println(text_search.findChar('e', "Hanyang"));
}
}
즉, 반복문의 제어문은 상황에 따라 예외처리하는 방식이 달라지는 것을 알 수 있다.
어떤 예외 처리가 답이다 가 아닌, 반복하는 상황에 적합한 예외를 사용해 프로그램을 설계하는 것이 올바르다.
프로그램 설계는 답이 없고, 좋은 방법들 중 하나를 택하는 것.
for 루프
for 루프의 기본적인 형태는 아래와 같다.
for (int count = 0; count < n; count += 1) {
// 코드
}
# 문자열 검색 - for 루프 예시 코드
public class TextSearch {
public int findChar(char c, String s) {
int index;
for (index = 0; index < s.length() && s.charAt(index) != c; index++)
// loop invariant: s[0], .., s[index-1]은 모두 c가 아님
;
if (index == s.length())
index = -1;
return index;
}
public static void main(String[] args) {
TextSearch text_search = new TextSearch();
System.out.println(text_search.findChar('a', "Hanyang"));
System.out.println(text_search.findChar('e', "Hanyang"));
}
}
출력 값이 1이면, 문자열의 문자 검색 성공
출력 값이 -1이면, 문자열의 문자 검색 실패
for 루프로 프로그램을 설계하면, 제어문을 반복문 내에서 할당할 수 있어,
간결성을 높힐 수 있다.
사례학습 - 상자 속 공 굴리기 애니메이션 with MVC Architecture
상자 속 공 굴리기 애니메이션의 MVC 아키텍처 - Cotroller, ViewOut, Model
Start : BounceBall
Controller : BounceBallController
VIewOut : BounceBallBallViewOut & BounceBallBoxViewOut & BounceBallControllerViewOut
Model : BounceBallMoveBallModel & BounceBallBoxModel
으로 MVC 아키텍처를 설계했다.
헤당 프로그램은 설계 순서에 따라 포스팅을 하도록 하겠다.
Model 설계
Model - BounceBallBoxModel 설계
/** BounceBallBoxModel - 공이 돌아다니는 상자 */
public class BounceBallBoxModel {
private int BOX_SIZE; // 상자의 크기
/** Constructor Method - 상자 생성
* @param size - 상자의 크기 */
public BounceBallBoxModel(int size) {
BOX_SIZE = size;
}
/** inHorizontalContact - 공이 x축 방향으로 좌/우 벽에 도달 여부를 리턴
* @param x_position - 공의 x 좌표
* @return true, 공의 x 좌표가 좌우 벽의 x 좌표와 같거나 벗어났으면 true, 그렇지 않으면 false */
public boolean inHorizontalContact(int x_position) {
return (x_position <= 0 ) || (x_position >= BOX_SIZE);
}
/** inVerticalContact - 공이 y축 방향으로 아래/위 벽에 도달 여부를 리턴
* @param y_position - 공의 y 좌표
* @return true, 공의 y 좌표가 아래위 벽의 y 좌표와 같거나 벗어났으면 true, 그렇지 않으면 false */
public boolean inVerticalContact(int y_position) {
return (y_position <= 0 ) || (y_position >= BOX_SIZE);
}
/** sizeOf - 상자의 크기를 리턴 */
public int sizeOf() {
return BOX_SIZE;
}
}
상자 속 공 굴리기 애니메이션 실행에 필요한 정보인
Box Size정보와 Box에 대한 동적 정보를 처리해준다.
Box에 공이 닿았는가, 닿지않았는가? 에 대한 정보를 처리해준다.
Model - BounceBallMoveBallModel 설계
/** BounceBallMoveBallModel - 2차원 상자에서 움직이는 공 */
public class BounceBallMoveBallModel {
private int x_pos; // 공의 중심 x 좌표
private int y_pos; // 공의 중심 y 좌표
private int radius; // 공의 반지름
private int x_velocity = +5; // 속도 x축
private int y_velocity = +2; // 속도 y축
private BounceBallBoxModel container;
/** Contructor Method - 공 만들기
* @param x_initial - 공의 중심 x 좌표
* @param y_initial - 공의 중심 y 좌표
* @param r - 공의 반지름
* @param box - 공이 살고 있는 상자 */
public BounceBallMoveBallModel(int x_initial, int y_initial, int r, BounceBallBoxModel box) {
x_pos = x_initial;
x_pos = y_initial;
radius = r;
container = box;
}
/** xPosition - 공의 x축 위치 리턴 */
public int xPosition() {
return x_pos;
}
/** yPosition - 공의 y축 위치 리턴 */
public int yPosition() {
return y_pos;
}
/** radiusOf - 공의 반지름 리턴 */
public int radiusOf() {
return radius;
}
/** move - time_unit 만큼 공을 이동, 벽에 부딪치면 방향을 바꿈
* @param time_units - 프레임 사이의 시간 */
public void move(int time_units) {
x_pos = x_pos + x_velocity * time_units;
if (container.inHorizontalContact(x_pos))
x_velocity = - x_velocity;
y_pos = y_pos + y_velocity * time_units;
if (container.inVerticalContact(y_pos))
y_velocity = - y_velocity;
}
}
상자 속에서 움직이는 공에 대한 정보를 처리해준다.
그리고, 상자 속 움직이는 공에 대한 처리로 공에 대한 정보를 제공한다.
# Model 테스트하기
협업 개발을 하면서, 구성한 Model에 대해 실행을 해볼 수 있다.
그래서, 구성한 Model이 원하는 대로 작동하는 지 테스트를 해볼 수 있다.
ViewOut을 구성하지 않았기에, 콘솔 환경에서만 테스트가 가능하다는 사실을 이해
public class TestModel {
public static void main(String[] args) {
Box box = new Box(50);
MovingBall ball = new MovingBall(25, 25, 10, box);
for (int i = 0; i < 10; i++) {
ball.move(1);
System.out.print("x = " + ball.xPosition());
System.out.println(", y = " + ball.yPosition());
}
}
}
테스트 방법은
테스트 클래스를 구성해서, main 메소드를 구성해 Java 프로그램을 실행해본다.
ViewOut 설계
ViewOut - BounceBallBoxViewOut 설계
import java.awt.*;
/** BounceBallBoxViewOut - 상자를 그림 */
public class BounceBallBoxViewOut {
private BounceBallBoxModel box; // 상자 객체
/** Constructor BoxWriter
* @param b - 상자 객체 */
public BounceBallBoxViewOut(BounceBallBoxModel b) {
box = b;
}
/** paint - 상자 그리기
* @param g - 그래픽스 펜 */
public void paintComponent(Graphics g) {
int size = box.sizeOf();
g.setColor(Color.white);
g.fillRect(0, 0, size, size);
g.setColor(Color.black);
g.drawRect(0, 0, size, size);
}
}
해당 클래스는 상자 속 공굴리기 애니메이션에서 상자에 대한 출력을 담당한다.
그래서, 해당 클래스를 통해 상자에 대한 정보를 출력할 수 있게 만든다.
ViewOut - BounceBallBallViewOut 설계
import java.awt.*;
/** BounceBallBallViewOut - 움직이는 공을 그림 */
public class BounceBallBallViewOut {
private BounceBallMoveBallModel ball; // 공 객체
private Color balls_color; // 공의 색깔
/** Constructor BallWriter
* @param x - 공 객체
* @param c - 공의 색깔 */
public BounceBallBallViewOut(BounceBallMoveBallModel x, Color c) {
ball = x;
balls_color = c;
}
/** paint - 공 그리기
* @param g - 그래픽스 펜 */
public void paintComponent(Graphics g) {
g.setColor(balls_color);
int radius = ball.radiusOf();
g.fillOval(ball.xPosition() - radius, ball.yPosition() - radius,
radius * 2, radius * 2);
}
}
해당 클래스는 상자 속 공굴리기 애니메이션에서 상자 속 공에 대한 출력을 담당한다.
그래서, 해당 클래스를 통해 공에 대한 정보를 받아와 (Java Aplication에) Paint하게 된다.
ViewOut's Controller - BounceBallControllerViewOut 설계
import java.awt.*;
import javax.swing.*;
/** BounceBallControllerViewOut - 상자와 공의 애니메이션 디스플레이 */
public class BounceBallControllerViewOut extends JPanel {
private BounceBallBoxViewOut box_writer; // 상자 그리는 객체
private BounceBallBallViewOut ball_writer; // 공 그리는 객체
/** Constructor AnimationWriter - 상자와 공을 그리는 View 객체를 생성
* @param b - 상자 그리는 객체
* @param l - 공 그리는 객체
* @param size - 프레임의 크기 */
public BounceBallControllerViewOut(BounceBallBoxViewOut b, BounceBallBallViewOut l, int size) {
box_writer = b;
ball_writer = l;
JFrame f = new JFrame();
f.getContentPane().add(this);
f.setTitle("Bounce");
f.setSize(size, size+22);
f.setVisible(true);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
/** paintComponent - 공과 상자 그리기
* @param g - 그래픽스 펜 */
public void paintComponent(Graphics g) {
box_writer.paintComponent(g);
ball_writer.paintComponent(g);
}
}
ControllerViewOut은 ViewOut 클래스를 통제하는 역할이다.
그래서, 해당 클래스를 통해 선언한 ViewOut 클래스를 Controller 한다.
MVC 아키텍처는 상황에 따라 확장되어, 더욱 더 쳬계적인 프로그램을 설계한다는 사실을 알 수 있다
MVC 아키텍처 설계는 정답이 있는 게 아니라, 상황에 적합한 설계를 구상하는 것이다.
이번 프로그램 설계하면서도 알다시피, MVC 아키텍처는 프로그램에 따라 구성이 다름을 알 수 있다.
설계에는 정답이 없고, 좋은 방법 중에서 적절한 방법을 택해서 설계하는 것이다.
Controller - BounceBallController 설계
/** BounceBallController - 상자 안에서 움직이는 공 제어 */
public class BounceBallController {
private BounceBallMoveBallModel ball; // 공 객체 (Model)
private BounceBallControllerViewOut writer; // 애니메이션 객체 (Output-View)
/** Constructor BounceController 컨트롤러 초기화
* @param b - 공 객체 (Model)
* @param w - 애니메이션 객체 (Output-View) */
public BounceBallController(BounceBallMoveBallModel b, BounceBallControllerViewOut w) {
ball = b;
writer = w;
}
/** runAnimation - 내부 시계를 활용하여 애니메이션 구동 */
public void runAnimation() {
int time_unit = 1; // 애니메이션 스텝의 시간 단위
int painting_delay = 20; // 다시 그리기 사이의 지연 시간 간격
while (true) {
delay(painting_delay);
ball.move(time_unit);
System.out.println(ball.xPosition() + ", " + ball.yPosition());
writer.repaint();
}
}
/** delay - how_long millisecond 동안 실행 정지 */
private void delay(int how_long) {
try { Thread.sleep(how_long); }
catch (InterruptedException e) { }
}
}
상자 속 공굴리기 애니메이션을 통제하는 Controller 클래스이다.
Model에서 상자, 공에 대한 정보를 가져오고,
ViewOut에 가져온 상자, 공에 대한 정보를 넣어 Java Aplication을 실행 & 출력을 해준다.
Controller는 MVC 아키텍처에서의 통제역할이다.
Start - BounceBall 설계
import java.awt.*;
/** BounceBall - 애니메이션 객체를 생성하고 공 운동 시작 */
public class BounceBall {
// 상자 속 공굴리기 애니메이션의 main 클래스
public static void main(String[] args) {
// 모델 객체 생성
int box_size = 200;
int balls_radius = 6;
BounceBallBoxModel box = new BounceBallBoxModel(box_size);
// 공을 상자의 적절한 위치에 둠
BounceBallMoveBallModel ball = new BounceBallMoveBallModel((int)(box_size / 3.0),
(int)(box_size / 5.0),
balls_radius, box);
BounceBallBallViewOut ball_writer = new BounceBallBallViewOut(ball, Color.red);
BounceBallBoxViewOut box_writer = new BounceBallBoxViewOut(box);
BounceBallControllerViewOut writer = new BounceBallControllerViewOut(box_writer, ball_writer, box_size);
// 컨트롤러 객체를 생성하고 애니메이션 시작
new BounceBallController(ball, writer).runAnimation();
}
}
상자 속 공굴리기 애니메이션을 시작하는 Start 클래스이다.
해당 클래스에서 main 메소드르르 선언해뒀기에, Java 프로그램을 실행한다.
상자 속 공굴리기 애니메이션 만들기 끝!
실습1. 추가 기능 - 상자 속 공굴리기 애니메이션
파란색 공 추가하기
처음에 실습할 때는, 파란색 공을 위한 클래스를 생성해서
파란색 공을 위한 메소드를 따로 만드는 시도를했었다.
하지만, 실습하다가 이 방법이 아닌,
교수님은 MVC 설계한 파일은 유지하고,
Controller에서 파란색을 위한 "객체"를 선언해서
파란색 공을 추가하는 걸 볼 수 있었다.
기존에 함수형 기반언어인 node.js를 사용하다가, Java를 쓰다보니,
Java는 "객체"로써 프로그램이 설계되고 기능이 추가된다는 사실을 깨달았다.
node.js는 함수형 기반언어로 객체지향 언어이긴하지만,
Java 처럼 "객체지향"의 느낌이 아니긴했던 것 같다 ㅎㅎ...
이번 Java를 배우면서 Java의 프로그램 설계법은 어떠한지 차이를 확실히 느끼며,
개발환경에 따른 개발방법론을 찾아나가보자!
이번 실습에서 중요한 사실은 클래스를 객체로 선언하면, 그 객체는 프로그램 실행하는 동안 "고유한 객체"로 존재한다. 그리고, 동일한 클래스더라도, 서로 다른 변수에 (클래스)객체를 할당하면 동일한 클래스에 대해서도
서로 다른 두 객체가 존재하게 된다.
그럼, 파란색 공을 추가해서 Java GUI에 출력해보도록 하겠다.
다음은, 파란색 공을 추가할 때 체계적이고, 구체적으로 느껴지도록 설계한 순서대로 기록했다. - 참고하길 바란다.
이 순서가 답이 아니고, 상황에 따라 적합한 방법대로 개발을 하면 되겠다.
BounceBall 수정 - BounceBall 클래스를 파란색 공을 추가하기 위해 파란색 공을 위한 객체들을 추가했다.
import java.awt.*;
/** BounceBall - 애니메이션 객체를 생성하고 공 운동 시작 */
public class BounceBall {
// 상자 속 공굴리기 애니메이션의 main 클래스
public static void main(String[] args) {
// 모델 객체 생성
int box_size = 200;
int balls_radius = 6;
BounceBallBoxModel box = new BounceBallBoxModel(box_size);
// 공을 상자의 적절한 위치에 둠 - 공의 초기위치 설정
BounceBallMoveBallModel ball = new BounceBallMoveBallModel((int)(box_size / 3.0),
(int)(box_size / 5.0),
balls_radius, box);
BounceBallMoveBallModel blueBall = new BounceBallMoveBallModel(80,
150,
balls_radius, box);
BounceBallBallViewOut ball_writer = new BounceBallBallViewOut(ball, Color.red);
BounceBallBallViewOut blueBall_writer = new BounceBallBallViewOut(blueBall, Color.blue);
BounceBallBoxViewOut box_writer = new BounceBallBoxViewOut(box);
BounceBallControllerViewOut writer = new BounceBallControllerViewOut(box_writer, ball_writer, blueBall_writer, box_size);
// 컨트롤러 객체를 생성하고 애니메이션 시작
new BounceBallController(ball,blueBall, writer).runAnimation();
}
}
BounceBallController 수정 - 공 색깔별로 지정된 객체를 받아서 Model로 가서 공 위치를 업데이트하고,
ViewOut으로 가서 업데이트 된 공 위치를 출력하도록 Controller 했다.
/** BounceBallController - 상자 안에서 움직이는 공 제어 */
public class BounceBallController {
private BounceBallMoveBallModel ball; // 공 객체 (Model)
private BounceBallControllerViewOut writer; // 애니메이션 객체 (Output-View)
private BounceBallMoveBallModel blueBall;
/** Constructor BounceController 컨트롤러 초기화
* @param b - 공 객체 (Model)
* @param w - 애니메이션 객체 (Output-View) */
public BounceBallController(BounceBallMoveBallModel b, BounceBallMoveBallModel bb, BounceBallControllerViewOut w) {
ball = b;
blueBall = bb;
writer = w;
}
/** runAnimation - 내부 시계를 활용하여 애니메이션 구동 */
public void runAnimation() {
int time_unit = 1; // 애니메이션 스텝의 시간 단위
int painting_delay = 20; // 다시 그리기 사이의 지연 시간 간격
while (true) {
delay(painting_delay);
// 공 객체 업데이트
ball.move(time_unit);
blueBall.move(time_unit);
System.out.println(ball.xPosition() + ", " + ball.yPosition());
writer.repaint();
}
}
/** delay - how_long millisecond 동안 실행 정지 */
private void delay(int how_long) {
try { Thread.sleep(how_long); }
catch (InterruptedException e) { }
}
}
BounceBallControllerViewOut 수정 - Start로부터 받아진 색깔별 객체를 사용해서 "상자 속 공굴리기 애니메이션"이 구현되도록
ViewOut을 Controller한다.
import java.awt.*;
import javax.swing.*;
/** AnimationWriter - 상자와 공의 애니메이션 디스플레이 */
public class BounceBallControllerViewOut extends JPanel {
private BounceBallBoxViewOut box_writer; // 상자 그리는 객체
private BounceBallBallViewOut ball_writer; // 공 그리는 객체
private BounceBallBallViewOut blueBall_writer; // 파란색 공 그리는 객체
/** Constructor AnimationWriter - 상자와 공을 그리는 View 객체를 생성
* @param b - 상자 그리는 객체
* @param l - 공 그리는 객체
* @param size - 프레임의 크기 */
public BounceBallControllerViewOut(BounceBallBoxViewOut b, BounceBallBallViewOut l, BounceBallBallViewOut lb , int size) {
box_writer = b;
ball_writer = l;
blueBall_writer = lb;
JFrame f = new JFrame();
f.getContentPane().add(this);
f.setTitle("Bounce");
f.setSize(size, size+22);
f.setVisible(true);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
/** paintComponent - 공과 상자 그리기
* @param g - 그래픽스 펜 */
public void paintComponent(Graphics g) {
box_writer.paintComponent(g);
ball_writer.paintComponent(g);
blueBall_writer.paintComponent(g);
}
}
그럼 결과를 확인해보자 !
짜잔 ~ Java GUI로 상자 속 굴려지는 두 공(빨간색 공, 파란색 공)들을 확인할 수 있다.
이번 프로그램 설계 경험을 통해,
Starter 클래스에 대해 새롭게 생각하게 되었다.
Starter 클래스도, Controller 의 특성을 나눠가진다는 것을..
'CS 대학강의' 카테고리의 다른 글
[CS 1-2 | 이산수학] 알고리즘 9주차 (0) | 2022.10.11 |
---|---|
프로그램 설계 방법론 - 트러블 슈팅 [주사위 게임 과제] (0) | 2022.10.08 |
[CS 1-2 | 오픈소스 SW 기초] 네트워크 & Git 4주차 (2) | 2022.10.06 |
[CS 1-2 | 대학생을 위한 실용금융] 투자 7주차 (0) | 2022.10.05 |
[CS 1-2 | 대학생을 위한 실용금융] 저축과 세금 6주차 (0) | 2022.10.05 |