본문 바로가기
JAVA

[MVC] 계산기 : 예제

by amoomar 2022. 1. 18.
반응형

 

 

이전에 포스팅한 MVC 2까지의 내용을 응용하여 계산기 프로그램을 구현하고, GUI개념을 Java에 적용하여 버튼식 계산기 프로그램을 구현하였다.

 

 

 


 

 

 

1. MVC 2 내용 응용 _ 계산기 구현

 

1) 설계

: 코딩 전 구현할 내용 정리 및 설계에 대한 내용 정리

 

  1. 전체 흐름 파악
    • M -> int num1, String op(+,-), int num2, int res(결과값) 필요
    • V -> 입력, 출력메서드 필요
  2. MVC로 분할 : 사용자 입력 저장에 대해 두가지의 풀이방법 존재
    • 사용자 입력 멤버변수로 저장하기 : View에서 진행
    • 사용자 입력 메서드(void)로 저장하기 : ModelVO생성 후 진행

 

 

 


 

 

2) View

package view;

import java.util.InputMismatchException;
import java.util.Scanner;

// 범위 외 입력 예외처리 목적
class MyException extends Exception{
	
	MyException(String message){
		super(message);
	}
	
}

public class CalculatorView {
	
	//멤버변수(사용자의 입력) & 스캐너
	Scanner sc = new Scanner(System.in);
	MyException myExcep = new MyException("입력을 다시 확인하세요");
	String mainMsg = "1. 계산하기 \n2. 종료하기";
	
	//사용자입력 저장할 변수
	private int action;
	private int num1;
	private int num2;
	private String op;
	
	//게터세터
	public int getAction() {
		return action;
	}

	public void setAction(int action) {
		this.action = action;
	}

	public int getNum1() {
		return num1;
	}

	public void setNum1(int num1) {
		this.num1 = num1;
	}

	public int getNum2() {
		return num2;
	}

	public void setNum2(int num2) {
		this.num2 = num2;
	}

	public String getOp() {
		return op;
	}

	public void setOp(String op) {
		this.op = op;
	}

	// 시작화면
	public void StartView() {
		
		System.out.println("===계산기===");
		System.out.println(mainMsg);
		System.out.println("===========");
		
		while(true) {
			
			try {
				
				System.out.println(">>");
				int action = sc.nextInt();
				
				if(action<1 || action>2) {
					throw myExcep;
				}
				this.action = action;
				break;
				
			}catch(InputMismatchException e) {
				sc.nextLine();
				System.out.println("*정수로 입력하세요*");
			}catch(Exception e) {
				System.out.println(e.getMessage());
			}
		}
	}
	
	// 정수1 입력
	public int num1() {
		
		while(true) {
			
			try {
				
				System.out.println("첫번째 정수 : ");
				int num1 = sc.nextInt();
				
				this.num1 = num1;
				break;
				
			}catch(InputMismatchException e) {
				sc.nextLine();
				System.out.println("*정수로 입력하세요*");
			}catch(Exception e) {
				System.out.println(e.getMessage());
			}
			
		}
		return num1;
	}
	
	// 정수2 입력
	public int num2() {
		
		while(true) {
			
			try {
				
				System.out.println("두번째 정수 : ");
				int num2 = sc.nextInt();
				
				this.num2 = num2;
				break;
				
			}catch(InputMismatchException e) {
				sc.nextLine();
				System.out.println("*정수로 입력하세요*");
			}catch(Exception e) {
				System.out.println(e.getMessage());
			}
			
		}
		return num2;
	}
	
	// 연산자입력
	public String op() {
		
		while(true) {
			
			try {
				
				System.out.println("연산자 : ");
				String op = sc.next();
				
				if(op.equals("+") || op.equals("-")) {
					this.op = op;
					break;
				}
				if(op.equals("*") || op.equals("/")) {
					this.op = op;
					break;
				}
				
				throw myExcep;
				
			}catch(InputMismatchException e) {
				sc.nextInt();
				System.out.println("*연산자를 입력하세요*");
			}catch(Exception e) {
				System.out.println(e.getMessage());
			}
			
		}
		return op;
	}
	
	
	// 출력메서드
	public void print(Object obj) {
		for(int i=0; i<5; i++) {
			System.out.print("두구");
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println();
		System.out.println(obj);
	}
	
	public void endPrint() {
		System.out.println("★계산기를 종료합니다★");
	}
	
}

 

 

사용자의 입력을 멤버변수에 저장하는 방식으로 진행

 

 


 

3) Model

package model;

public class CalculatorModel {
	
	//멤버변수
	private int num1;
	private int num2;
	private String op;
	private int res;

	
	//getter&setter
	public int getNum1() {
		return num1;
	}
	public void setNum1(int num1) {
		this.num1 = num1;
	}
	public int getNum2() {
		return num2;
	}
	public void setNum2(int num2) {
		this.num2 = num2;
	}
	public String getOp() {
		return op;
	}
	public void setOp(String op) {
		this.op = op;
	}
	public int getRes() {
		return res;
	}
	public void setRes(int res) {
		this.res = res;
	}
	
	
	//계산메서드
	public int res(Object obj) {
		
		if (obj.equals("+")){//덧셈
			this.res = num1 + num2;
		} else if (obj.equals("-")){//뺄셈
			this.res = num1 - num2;
		} else if (obj.equals("*")) {//곱셈
			this.res = num1 * num2;
		} else if (obj.equals("/")) {//나눗셈
			this.res = num1 / num2;
		}
		return res;
		
	}

	
}

 


*기본생성자를 이용하여 작업 진행*

이때 생성자가 없을 경우, 멤버변수 초기화가 안되는 것을 유의할 것. 즉, setter를 호출해야한다.

 

 

 


 

4) Controller

package controller;

import model.CalculatorModel;
import view.CalculatorView;

public class CalculatorCtrl {
	//접근선언
	CalculatorModel model;
	CalculatorView view;
	
	//ctrl실행 메서드 : model과 view정보 불러오기
	public void ctrlStart () {
		model = new CalculatorModel();
		view = new CalculatorView();
	}
	
	
	// 앱실행 메서드
	public void appStart () {
		
		while(true) {
			
			view.StartView(); //main화면출력
			
			//메인에서 1 입력시 계산실행
			if(view.getAction()==1) {
				
				//view의 입력 -> model에 저장
				model.setNum1(view.num1());
				model.setOp(view.op());
				model.setNum2(view.num2());
				
				// syso(num1 + num2 = res); 과 같다
				view.print(model.getNum1()+model.getOp()+model.getNum2()
				+"="+model.res(model.getOp()));
			
			//메인에서 2 입력시 종료
			}else if(view.getAction()==2) {
			
				//종료문구 출력
				view.endPrint();
				break;
				
			}
		}

	}
}

 

 

 


 

 

5) 실행결과

package class01;

import controller.CalculatorCtrl;

public class Client {

	public static void main(String[] args) {
		
		CalculatorCtrl ctrl = new CalculatorCtrl();
		//데이터불러오기
		ctrl.ctrlStart();
		//앱실행
		ctrl.appStart();
		
	}
}

 

[출력화면 : -> 입력]

 

===계산기===
1. 계산하기 
2. 종료하기
===========
>>
1
첫번째 정수 : 
8
연산자 : 
*
두번째 정수 : 
9
두구두구두구두구두구
8*9=72
===계산기===
1. 계산하기 
2. 종료하기
===========
>>
종료
*정수로 입력하세요*
>>
2
★계산기를 종료합니다★

 

 

 


 

 

2.  GUI 자바응용_ 버튼식 계산기 구현

 

1) 배경이론

 

UI / UX

UI (User Interface) : "사용자를 마주하다"라는 의미로, 사용자가 앱 사용시 마주하는 디자인, 레이아웃, 기술적인 부분을 말한다. 상세하게는 줄간격, 폰트, 색상, 반응성, 입출력단계, 애니메이션 효과 등 여러 부분을 포함한다.

 

UX (User Experience) : "사용자의 경험을 녹이다"라는 의미로, 앱을 주로 사용하는 사용자들의 경험(가장 먼저 터치하는 화면, 사용자의 선택 플로우 등)들을 분석하여 그것을 더 편하고 효율적인 방향으로 프로세스가 진행될 수 있도록 하는 과정 및 결과를 뜻한다. UI에서 파생되었다고 보아도 무관하다.

 

UI / UX에서는 사용자가 서비스를 이용하는 흐름을 잘 이해하는 것이 중요하다.

즉, 사용자 편의성을 항상 고려해야한다.

 

참고 : https://brunch.co.kr/@aw2sum/36

 

UI / UX 의 차이는?

아무리 보아도 혼란해... | UI / UX 이 두 가지의 차이에 대해서 잘 모르는 사람들이 많다. 솔직히 나도 이 두가지의 개념 구분은 최근에야 하였고, 그 내용을 정리하고자 브런치에 남기려고 한다.

brunch.co.kr

 

 

 

GUI (Graphical User Interface)

직역하면 "그래픽 사용자 인터페이스"이다.

사용자 편의성을 고려하여 입출력 등의 기능을 알기 쉬운 아이콘, 버튼 등그래픽으로 나타낸 것이다.

 

참고 : https://blog.naver.com/PostView.nhn?blogId=anedthh&logNo=221990305012&categoryNo=0&parentCategoryNo=0 

 

GUI란? (graphical user interface, GUI) 구이☆★

줴유ㅇㅏ이인데 자꾸 구이라고 하게 된다☆★ GUI (Graphical User Interface, 그래픽 사용자 인터페...

blog.naver.com

 

 

컴포넌트

제품의 모듈과 유사한 개념으로, 소프트웨어상의 모듈이라고 할 수 있다.

독립적인 기능을 수행하도록 구현하여, 이를 다른 부분에 응용 or 삽입하여 사용할 수 있도록 한다.(핸드폰 탈부착 배터리의 기능과 유사!) 컴포넌트는 소프트웨어의 재사용의 중요성과 필용성을 위해 나온 기술이며, 이로인해 개발시간 단축, 개발비용 절감의 이점을 이행할 수 있다. 추가로 입력을 강제할 수 있다는 특징이 있다.

(ex. 전화번호 입력시 [  ][  ][  ]or[  -  -  ]따위로 입력을 구체적으로 정의)

 

참고 : https://mommoo.tistory.com/55

 

컴포넌트(Component)란?

컴포넌트(Component)개념의 등장배경 과 의미에 대해 기술한다. 컴포넌트 개념의 유래 많은 하드웨어 제품들은 각각 독립된 기능을 가진 모듈로 만들어진다. 이 제품들은 회사 상관없이 서로 조합

mommoo.tistory.com

 

 

 

 


 

 

2) View

package view;

import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

// 상속을 통해 Frame으로 만듦!
public class CalcView2 extends JFrame{
	
	public JTextField n1, n2;
	public JComboBox<String> op;
	public JButton btn;
	public JLabel res;
	
	//위의 요소들을 여기에 붙인다.
	JPanel panel; 
	
	// *생성자 내부에서 멤버변수 초기화 진행*
	public CalcView2() {
		
		setTitle("계산기 MVC 실습");
		
		n1 = new JTextField(5); //생성자 내부의 칸 크기 설정
		n2 = new JTextField(5); //생성자 내부의 칸 크기 설정
		op = new JComboBox(); //스크롤박스
		
		// 스크롤박스 내부의 문자표시
		op.addItem("+");
		op.addItem("-");
		op.addItem("/");
		op.addItem("x"); //*의 표시
		btn = new JButton("계산하기"); //버튼글씨
		res = new JLabel(); //버튼
		
		// 모든 GUI View는 레이아웃을 설정한다.
		setLayout(new FlowLayout()); //그리드 같은 것
		
		panel = new JPanel();
		panel.add(n1);
		panel.add(op);
		panel.add(n2);
		panel.add(btn);
		
		add(panel);
		add(res);
		
		setVisible(true); //화면에 안뜨는게 기본
		//창의 X버튼을 눌렀을때, 종료되도록한다. -> 미선언시 X눌러도 미종료
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
		
	}
	
	// 리셋
	public void reset() {
		n1.setText(""); //공백없이 진행
		n2.setText(""); //공백없이 진행
	}
	
}

 

 : 별도의 필기 없이 필드의 주석을 통해 내용 파악이 가능하다.

 

 

 


 

 

3) Model

package model;

public class CalcModel2 {

	//멤버변수
	private int n1, n2, res;
	private String op;

	//생성자
	public CalcModel2(int n1, int n2, String op) {
		super();
		this.n1 = n1;
		this.n2 = n2;
		this.op = op;
		
		//model생성자에 인자가 들어오면
		//계산메서드 진행을 통해 res값 setting!
		calculate(); 
	}

	// 메서드에 값변경에 대한 로직이 들어있는 경우.
	// 즉, 멤버변수의 값을 초기화하는 로직은 private을 통해 감출 수 있다.
	// but, 로직코드는 공개하기
	private void calculate() {
		if (op.equals("+")){
			this.res = plus(n1, n2);
		} else if (op.equals("-")){
			this.res = minus(n1, n2);
		} else if (op.equals("/")){
			this.res = divide(n1, n2);
		} else if (op.equals("x")){
			this.res = multip(n1, n2);
		}
	}

	// 순수 알고리즘 코드! == 컴포넌트
	// 이러한 로직코드는 재사용을 위해 open하는 것이 좋다!
	public int plus(int n1, int n2) {
		return n1 + n2;
	}
	public int minus(int n1, int n2) {
		return n1 - n2;
	}
	public int divide(int n1, int n2) {
		return n1 / n2;
	}
	public int multip(int n1, int n2) {
		return n1 * n2;
	}

	//결과 출력하는 메서드
	public String printRes() {
		return n1 + " " + op + " " + n2 + "=" + res;
	}

	// getter & setter
	public int getN1() {
		return n1;
	}

	public void setN1(int n1) {
		this.n1 = n1;
	}

	public int getN2() {
		return n2;
	}

	public void setN2(int n2) {
		this.n2 = n2;
	}

	public int getRes() {
		return res;
	}

	public void setRes(int res) {
		this.res = res;
	}

	public String getOp() {
		return op;
	}

	public void setOp(String op) {
		this.op = op;
	}


}

 

 : 별도의 필기 없이 필드의 주석을 통해 내용 파악이 가능하다.

 

 

 


 

 

4) Controller

package controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import model.CalcModel2;
import view.CalcView2;

// FrameView인 경우 버튼에 대한 반응 구현 필수
// 인터페이스를 통해 강제 할 수 있다. 
// * 하단 필기내용 참고 *
public class CalcCtrl2 implements ActionListener{ //Listener : 모니터링(감지체크)

	CalcView2 view;
	public CalcCtrl2 () {
		view = new CalcView2();
		
		//뷰에 현재 구현한 Ctrl를 더하는(연결) 작업
		view.btn.addActionListener(this); 
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
	// e = 액션 그 차제 : 버튼을 누른 행위
		
		if(e.getSource()==view.btn) { // if,버튼을 눌렀다면
			
			//사용자의 정보의 저장은 String으로 진행됨
			String n1 = view.n1.getText(); 
			String n2 = view.n2.getText(); 
			String op = view.op.getSelectedItem().toString();
			
			// 유효성체크
			if(!n1.matches("[0-9]+") || !n2.matches("[\\d]+")) {
				//정규식
				view.res.setText("정수만 입력하세요");
				view.reset();
				return;
			} else if (op.equals("/") && n2.equals("0")) {
				view.res.setText("불능");
				view.reset();
				return;
			}

			CalcModel2 calc = new CalcModel2(Integer.parseInt(n1), Integer.parseInt(n2), op);
			
			String res = calc.printRes();
			view.res.setText(res);
			view.reset();
		}
		
	}
	
	
}

 

* 필기 : ActionListener *

ActionListener이라는 interface 안에 actionPerformed를 @Override해서 해당 메소드안에 실행코드를 입력하게 되면, 지정한 Component의 액션이 발생했을 때, 실행코드가 작동하게 된다.

 

 


5) 실행결과

: 컨트롤러의 초기화만으로 출력 가능

package class01;

import controller.CalcCtrl2;

public class Client2 {
	public static void main(String[] args) {

		new CalcCtrl2();
		
	}
}

 

 

  1. 실행 가능한 메서드
    콘솔이 빨강색으로 실행중임을 알 수 있다.
  2. 정상입력시
    정상입력시의 출력화면
  3. 비정상입력시

타입이 맞지 않은 입력시의 출력화면

 

 

 


 

반응형