본문 바로가기
코딩도전기/MVC

CODO Day19_JAVA_MVC(Interface 다중 구현/익명객체/Interface 상속)

by 코도꼬마 2023. 2. 27.

Interface 다중 구현(코드리뷰 포함)

  • interface는 다중구현(multiple implements)이 가능
  • Interface를 구현한 클래스해당 인터페이스 형태에 들어갈 수 있음(객체화한 인터페이스의 변수에 넣을 수 있음)

Written by zer0box

  • Attack(interface)
package kr.co.web.model;

public interface Attack {
	public String normal();
	public String special();
}

 

  • Defense(interface)
package kr.co.web.model;

public interface Defense {	
	public String block();
	public String avoid();
}

 

  • Character(class)
    • 인터페이스를 구현받은 클래스에서 변경이 필요할 경우 인터페이스도 수정해야 하는데
      소규모 프로젝트에서는 인터페이스 사용이 불필요한 작업임
    • 인터페이스는 규격을 사용하는 클래스가 많은 대형 프로젝트에서 유용
      1000개의 클래스에서 special 메서드를 300개 클래스가 사용한다고 가정하면
      인터페이스를 구현받지 않고 각각의 메서드로 만들었다면 하나씩 찾아서 수정하기 어려움
      인터페이스 구현 시 인터페이스에서 수정하면 해당 메서드를 구현받은 클래스는 자동으로 수정되거나 클래스에 빨간줄로 표시되어 찾기 쉬움
package kr.co.web.model;

public class Character implements Attack, Defense {  //Attack, Defense 인터페이스를 implements로 다중 구현했습니다.

	@Override
	public String block() {                              

		return "캐릭터가 공격을 막는다.";
	}

	@Override
	public String avoid() {
		
		return "캐릭터가 공격을 회피한다.";
	}

	@Override
	public String normal() {
		
		return "캐릭터가 일반 공격을 한다";
	}

	@Override
	public String special() {  //void타입을 String타입으로 변경
		
		return "캐릭터가 특수 공격을 한다";
	}
}

 

  • index(jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style></style>
</head>
<body>
<!-- 폼을 하나 만들어주었고 액션속성의 값은 추후에 넣어줄 것이기 때문에 비워둡니다. -->
   <form action=""> 
<!-- 액션선택을 할 수 있는 id가 action인 select태그와 종류를 선택할 수 있는 이름이 class인 select태그를 만들어 줍니다.-->   
      액션 선택 : 
      <select id ="action">                            
         <option value="attack">공격</option>
         <option value="defense">방어</option>
      </select>
      종류 :
      <select name="class">       
      	<option value="normal">일반공격</option>
      	<option value="special">특수공격</option>
      </select>
<!-- 버튼태그를 하나 만들어 준 후 클릭했을 때 form의 값을 전송하지 않도록 type을 button으로 설정해주고  -->
<!-- 클릭했을 때 go함수를 실행하도록 했습니다. -->
      <button type="button" onclick="go()">전송</button>  
   </form>  
<!-- 마지막에 실행 내용을 출력할 수 있도록 el태그를 넣어주었습니다. -->
   <h3>${msg}</h3>                                         
</body>
<script>
	/* action에서 값 선택 시 
	attack을 선택할 경우 종류에
	<option value="normal">일반공격</option>
	<option value="special">특수공격</option>가 나타나고, 
	deffense를 선택한 경우
	<option value="avoid">회피</option>
	<option value="block">막기</option>가 나타나야 한다 
	*/
   
   //1. id="action"에 이벤트 생성(change)
   $('#action').on('change',function(){ //아이디가 액션인 태그에 chage 이벤트를 걸어주었습니다.                     
      //var action = $(this).val();
      //console.log(action);
      
      //2. 이벤트 발생 시 name="class"에 option 추가
// 액션태그의 값이 변경될 때마다 종류태그의 내용이 변동될 수 있도록 값을 넣어주기 위해 content라는 변수를 선언해줍니다.     
      var content ='';   

//위의 태그 값이 attack일 경우 아래의 내용이 종류 태그의 옵션값으로 들어갈 수 있도록 content 변수에 넣어줍니다.
      if($(this).val()=='attack'){ 
         content = '<option value="normal">일반공격</option>';
         content += '<option value="special">특수공격</option>';
//태그 값이 attack이 아닐 경우 아래의 값이 나타날 수 있도록 동일하게 content 변수에 넣어줍니다.         
      }else{                                                              
         content = '<option value="avoid">회피</option>';
         content += '<option value="block">막기</option>';
      }
      //content변수에 저장된 값을 종류태그의 html에 넣어주었습니다.
      $('select[name="class"]').html(content);                           
   });  //이로써 액션태그의 값이 변경될 때 마다 종류태그의 옵션값이 변경되도록 해주었습니다.                                                                   

   function go(){ //버튼을 클릭했을 때 실행할 go 함수를 선언했습니다.                                                   
      // 1. id="action"의 값이 form의 action 속성에 들어간다.           
      var action = $('#action').val(); //액션태그의 값을 변수 action에 넣어주고
      $('form').attr('action',action); //폼태그의 액션속성의 값을 action 변수로 넣어줍니다. 
      
    //2. form이 submit 된다.
      $('form').submit(); //마지막으로 폼태그의 값을 submit함수를 이용해 다른 리소스로 넘겨줍니다.  
   }   
</script>
</html>

 

  • MainController(class)
    • http://localhost:8080/06_multimpl/attack  >> URL
    • 06_multimpl/attack                                   >>  URI
    • attack?class=normal                                >>  parameter
package kr.com.web.coltroller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.co.web.model.Character;

//애노테이션으로 서버에 주소가 "/attack","/defense"를 포함할 경우 메인컨트롤러로 넘어올 수 있도록 설정해주었습니다.
@WebServlet(urlPatterns = {"/attack","/defense"})  

//메인컨트롤러 클래스는 HttpServlet 추상클래스를 상속받아 sever와 java가 Request, Response를 주고 받을 수 있도록 해주었습니다.
public class MainController extends HttpServlet {      

	@Override  //get 속성값으로 들어온 파라메터 값을 받을 수 있도록 doGet함수를 오버라이드 해줍니다.
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)   
			throws ServletException, IOException {
		
		//parameter
        //getParameter를 이용하여 종류 태그의 값을 가져와 cls 변수에 넣어주었습니다.
		String cls = req.getParameter("class");             
		
        
		//uri
        //getRequestURI함수를 이용해 서버주소를 가져와 uri변수에 넣어주었습니다.
		String uri = req.getRequestURI();                 
		
		
		//전체 주소(uri)에서 요청주소(addr)만 가져오기
        //getContextPath함수로 서버의 프로젝트path만 가져와 cxt변수에 넣어줍니다.
		String cxt = req.getContextPath();               
		
//요청주소를 가져오기 위해 substring함수를 이용하여 위에서 가져온 uri에서 호스트주소와 cxt의 길이를 뺀 나머지 주소값을 addr변수에 저장해주었습니다.        
		String addr = uri.substring(cxt.length());        
//서버에서 선택한 종류태그의 값으로 Character클래스의 함수가 실행되었을 때 리턴값을 저장할 수 있도록 String타입의 result 변수를 선언해주었습니다.	                      
		String result = "";                            
//Character 클래스의 함수를 이용하기 위해 객체화시켜주었고 다른 패키지의 클래스를 객체화하기 위해 import 해주었습니다.		                                               
		Character ch = new Character();   
//액션태그의 선택값에 따라 변경된 종류태그의 값을 저장하기 위해 if-else함수를 선언했습니다.        
		//요청이 /attack일 경우             
		if(addr.equals("/attack")) { //addr변수의 문자열이 /attack이고 
			//class가 normal일 경우
			if(cls.equals("normal")) { //종류태그의 문자열이 normal일 경우 
				result = ch.normal(); //Character 클래스 normal함수의 return값을 result 변수에 넣어주고 
			}else {
				result = ch.special(); //아닐 경우 special함수의 return값을 result변수에 넣어줍니다.
			}
		}else{//아닐 경우  //같은 방법으로 addr의 값이 /attack이 아닐 경우 
			//class가 avoid일 경우
			if(cls.equals("avoid")) {
				result = ch.avoid(); //avoid, block함수의 return값을 변수에 넣어주었습니다.
			}else {
				result = ch.block();
			}
		} 
		//System.out.println("result : "+result);   
//setAttribute 함수로 index.jsp 파일에 보낼 response객체에 msg라는 이름으로 result 값을 넣어줍니다.
		req.setAttribute("msg", result); 
//response 객체는 값을 전송할 수 없기 때문에 Response 객체를 Request 객체와 함께 보낼 수 있도록 getRequestDispatcher함수를 사용해 경로를 index.jsp로 지정해주었습니다.
		RequestDispatcher dis = req.getRequestDispatcher("index.jsp");   
		dis.forward(req, resp); //forward함수를 사용하여 request객체를 담고 있는 변수 req와 response객체를 담고 있는 변수 resp의 값을 전송해줍니다.                                             
	}
}

 

 

 

익명객체 (Anonymous Instance)

  • Interface는 익명객체를 활용 
  • 익명(Anonymous) 객체는 말 그대로 이름이 없는 객체 
  • 임의적으로 익명클래스를 생성하여 객체화하여 사용한 후 사라짐
  • 하나의 익명클래스는 하나의 익명객체만 객체화 할 수 있음(1클래스 1익명객체)

 

  • Attact
package kr.co.web.model;

public interface Attact {	
	public String normal();
	public String special();
}

 

  • Defense
    • 이번에는 Defense를 구현하지 않고 MainController 클래스에서 객체화 할 예정
package kr.co.web.model;

public interface Defense {	
	public String block();
	public String avoid();
}

 

  • Character
package kr.co.web.model;

public class Character implements Attact {   
	@Override
	public String normal() {
		return "캐릭터가 일반 공격을 한다";
	}

	@Override
	public String special() {
		return "캐릭터가 특수 공격을 한다";
	}
}

 

  • index
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style></style>
</head>
<body>
	<form action="">
		액션선택 : 
		<select id="action">
			<option value="attack">공격</option>
			<option value="defense">방어</option>
		</select>
		종류 :
		<select name="class">
			<option value="normal">일반공격</option>
			<option value="special">특수공격</option>
		</select>
		<button type="button" onclick="go()">전송</button>
	</form>
	<h3>${msg}</h3>
</body>
<script>                                     
	$('#action').on('change',function(){   
		
		var content = '';
		console.log($(this).val());
		
		if($(this).val() == 'attack'){
			content = '<option value="normal">일반공격</option>';
			content += '<option value="special">특수공격</option>';
		}else{
			content = '<option value="avoid">회피</option>';
			content += '<option value="defense">막기</option>';
		}
		$('select[name="class"]').html(content);
	})
	
	function go(){
		var action = $('#action').val();
		$('form').attr('action',action);
		$('form').submit();
	}
</script>
</html>

 

  • MainController
    • 인터페이스는 스스로 객체화할 수 없기 때문에 인터페이스(기생)를 구현해줄 클래스가 필요함(기생)
    • Defense 인터페이스는 익명객체로 사용할 예정(함수명은 있지만 클래스가 없어서 익명객체)
      객체화 시 반드시 클래스가 있어야 하지만 현재는 임시로 익명클래스를 생성해 객체화 하였음
package kr.co.web.controller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.co.web.model.Character;
import kr.co.web.model.Defense;

@WebServlet(urlPatterns = {"/attack","/defense"})
public class MainController extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {
		
		String cls = req.getParameter("class");
		String uri = req.getRequestURI();
		//System.out.println(cls);
		//System.out.println(uri);
		
		String cxt = req.getContextPath();
		System.out.println(cxt);
		String addr = uri.substring(cxt.length());
		System.out.println(addr);
		String result = "";
		
		Character ch = new Character();
		if(addr.equals("/attack")) {
			if(cls.equals("normal")) {
				result = ch.normal();
			}else {
				result = ch.special();
			}
		}else {
			//익명 객체(클래스)를 이용하여 Defense 인터페이스 객체화
			Defense def = new Defense() {
				
				@Override
				public String block() {					
					return "캐릭터가 공격을 막는다(익명객체 사용)";
				}
				
				@Override
				public String avoid() {					
					return "캐릭터가 공격을 회피한다(익명객체 사용)";
				}
			};
			if(cls.equals("avoid")) {
				result = def.avoid();
			}else {
				result = def.block();
			}
		}
		System.out.println(result);
		req.setAttribute("msg", result);
		RequestDispatcher dis = req.getRequestDispatcher("index.jsp");
		dis.forward(req, resp);
	}
}

 

 

 

 

Interface 상속

  • Interface도 상속 가능
  • Class의 상속과 달리 다중상속이 가능
  • interface의 상속은 모듈 구조임(필요한 기능들을 모아서 합침)

 

class와 interface 상속의 차이점

Class Interface
순차적으로 기능을 extends해나가는
위계 구조
필요한 부분을 가져와 implements하는
모듈 구조(조합)
다중상속X 다중상속O

Written by zer0box
Written by zer0box

 

  • Action
package kr.co.web.model;

public interface Action extends Attack, Defense {	
	public String useItem();
	public String move();
	public String pickup();
}

 

  • Character
    • Action만 구현받았지만 Action이 상속받은 Attack과 defense의 추상 메서드도 구현됨
    • 상속은 내것처럼 사용하는 것이기 때문에 Action만 구현하여도 Attac과 Defense도 오버라이드 됨
package kr.co.web.model;

public class Charactor implements Action {	
	@Override
	public String normal() {
		return "일반공격을 한다";
	}

	@Override
	public String special() {
		return "특수 공격을 한다";
	}

	@Override
	public String block() {
		return "공격을 막는다";
	}

	@Override
	public String avoid() {
		return "공격을 회피한다";
	}

	@Override
	public String useItem() {
		return "아이템을 사용한다";
	}

	@Override
	public String move() {
		return "이동한다";
	}

	@Override
	public String pickup() {
		return "아이템을 줍는다";
	}
}

 

  • index
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<style></style>
</head>
<body>
	<form>
		액션선택 :
		<select id="action">
			<option value="attack">공격</option>
			<option value="defense">방어</option>
			<option value="common">공통행동</option>
		</select>
		
		종류 : 
		<select name="class">
			<option value="normal">일반공격</option>
			<option value="special">특수공격</option>
		</select>
		<button type="button" onclick="go()">전송</button>
	</form>
	<h3>${msg}</h3>
</body>
<script>
	$('#action').on('change',function(){
		var action = $(this).val();
		var content = '';
		
		if($(this).val() == 'attack'){
			content = '<option value="normal">일반공격</option>';
			content += '<option value="special">특수공격</option>';
		}else if($(this).val() == 'defense'){
			content = '<option value="block">막기</option>';
			content += '<option value="avoid">회피</option>';
		}else{
			content = '<option value="useItem">아이템사용</option>';
			content += '<option value="move">이동</option>';
			content += '<option value="pick">줍기</option>';
		} 
		$('select[name="class"]').html(content);		
	})
    
	function go() {
		var action = ($('#action').val());
		$('form').attr('action',action);
		$('form').submit();
	}
</script>
</html>

 

  • MainController
package kr.co.web.controller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.co.web.model.Charactor;

@WebServlet(urlPatterns = {"/attack","/defense","/common"})
public class MainController extends HttpServlet {	
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {
		
		String cls = req.getParameter("class");
		String uri = req.getRequestURI();
		
		String cxt = req.getContextPath();
		
		String addr = uri.substring(cxt.length());
		String result = "";
		
		
		Charactor ch = new Charactor();
		
		if(addr.equals("/attack")) {
			if(cls.equals("normal")) {
				result = ch.normal();
			}else {
				result = ch.special();
			}
		}else if(addr.equals("/defense")) {
			if(cls.equals("block")) {
				result = ch.block();
			}else {
				result = ch.avoid();
			}
		}else {
			if(cls.equals("useItem")) {
				result = ch.useItem();
			}else if(cls.equals("move")){
				result = ch.move();
			}else {
				result = ch.pickup();
			}
		}
		req.setAttribute("msg", result);
		RequestDispatcher dis = req.getRequestDispatcher("index.jsp");
		dis.forward(req, resp);
	}
}