Interface 다중 구현(코드리뷰 포함)
- interface는 다중구현(multiple implements)이 가능
- Interface를 구현한 클래스는 해당 인터페이스 형태에 들어갈 수 있음(객체화한 인터페이스의 변수에 넣을 수 있음)
- 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 |
- 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);
}
}
'코딩도전기 > MVC' 카테고리의 다른 글
CODO Day23_JAVA_MVC(Exception) (0) | 2023.03.06 |
---|---|
CODO Day22_JAVA_MVC(String) (0) | 2023.03.06 |
CODO Day20~21_JAVA_MVC(추상화의 장점/다형성) (0) | 2023.02.28 |
CODO Day18_JAVA_MVC(Abstract(추상화)) (0) | 2023.02.24 |
CODO Day17_JAVA_MVC(Model2/상속*) (0) | 2023.02.23 |