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

CODO Day20~21_JAVA_MVC(추상화의 장점/다형성)

by 코도꼬마 2023. 2. 28.

추상화의 장점

  • 인터페이스와 추상화는 개발 시 전체적인 규격을 만들어 줌
  • 추상화를 하지 않을 경우 중복코드가 발생하기 때문에 번거로움을 감소시키기 위해 추상화 사용
  • 인터페이스와 추상화를 활용하면 모듈 간의 결합도(coupling)를 감소시킴(면접질문*)
  • 규격이 있으면 서로 다른 것들끼리 충돌없이 사용 할 수 있음  ex) C타입 충전기
    • 결합도 : 서로 다른 모듈 간에 상호의존하는 정도/연관된 관계
                    변형을 줄 때 주변에 손상을 미치는 정도(분리했을 때 리스크가 큰 것을 결합도가 높다고 함)
                    ex) 결합도가 높은 것(신체) VS 결합도가 낮은 것(로봇)
    • 응집도 : 결합도에 대응 / 응집도는 한 모듈 내부의 처리요소들이 서로 관련되어 있는 정도
    • 응고결저 응집도는 높고 결합도는 낮은 것이 좋음

Written by zer0box

 

  • Vingsu<<interface>>
    • jdk 1.8미만에서는 default 매서드가 지원되지 않기 때문에 추상클래스를 사용하는 것이 적합
package kr.co.web.model;

public interface Vingsu {
	
	public default void iceFlake() {
		System.out.println("갈아둔 얼음을 넣는다");
	}
	
	public default void milk() {
		System.out.println("멸균우유를 넣는다");
	}
	
	public default void redBean() {
		System.out.println("팥을 넣는다");
	}
	
	public default void jelly() {
		System.out.println("젤리를 넣는다");
	}	
	public void etc();
}

 

  • RedBeanVingsu
package kr.co.web.model;

public class RedBeanVingsu implements Vingsu {

	@Override
	public void etc() {
		System.out.println("추가 첨가 없음");		
	}
}

 

  • ChocoVingsu
package kr.co.web.model;

public class ChocoVingsu implements Vingsu {

	@Override
	public void etc() {		
		System.out.println("초코시럽을 넣는다");
	}
}

 

  • CookieVingsu
package kr.co.web.model;

public class CookieVingsu implements Vingsu {

	@Override
	public void etc() {
		System.out.println("쿠키를 넣는다");
	}
}

 

  • FruitVingsu
package kr.co.web.model;

public class FruitVingsu implements Vingsu {

	@Override
	public void etc() {
		System.out.println("과일을 넣는다");
	}
}

 

  • VingsuMachine
    • 인터페이스를 구현받은 클래스는 인터페이스 데이터타입의 변수에 들어갈 수 있다(다형성)
    • 객체화 할 때 변수에 담에서 넣어줄 수도 있지만 매개변수 위치에 바로 넣어줄 수 있음(그릇없이)
package kr.co.web.model;

public class VingsuMachine {

	String name;
	
	public VingsuMachine(String name) {
		this.name = name;
	}
	//매개변수 자리에서 바로 객체화 해버림
	//Vingsu 타입에 ChocoVingsu, CookieVingsu, RedBeanVingsu, FruitVingsu가 들어갈 수 있다
	public String makeVingsu(Vingsu vingsu) {
		vingsu.iceFlake();
		vingsu.milk();
		vingsu.redBean();
		vingsu.jelly();
		vingsu.etc();
		return name + "가 완성되었습니다.";
	}	
}

 

  • 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="make" method="post">
		<select name="vingsu">
			<option value="팥빙수">팥빙수</option>
			<option value="초코빙수">초코빙수</option>
			<option value="쿠키빙수">쿠키빙수</option>
			<option value="과일빙수">과일빙수</option>
		</select>
		<input type="submit" value="주문"/>
	</form>
	<h3>${result}</h3>
</body>
<script></script>
</html>

 

  • VingsuController
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.ChocoVingsu;
import kr.co.web.model.CookieVingsu;
import kr.co.web.model.FruitVingsu;
import kr.co.web.model.RedBeanVingsu;
import kr.co.web.model.Vingsu;
import kr.co.web.model.VingsuMachine;

@WebServlet("/make")
public class VingsuController extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {

		req.setCharacterEncoding("UTF-8");
		String vingsu = req.getParameter("vingsu");
		System.out.println(vingsu);

		VingsuMachine vm = new VingsuMachine(vingsu);
		Vingsu vs = null;   //Vingsu vs = new Vingsu(); / vs = null;
		String result = "";

		switch (vingsu) {
		case "팥빙수":
			vs = new RedBeanVingsu();
			result = vm.makeVingsu(vs);
			break;
		case "초코빙수":
			vs = new ChocoVingsu();
			result = vm.makeVingsu(vs);
			break;
		case "쿠키빙수":
			vs = new CookieVingsu();
			result = vm.makeVingsu(vs);
			break;
		case "과일빙수":
			vs = new FruitVingsu();
			result = vm.makeVingsu(vs);
			break;
		}
		req.setAttribute("result", result);
		RequestDispatcher dis = req.getRequestDispatcher("index.jsp");
		dis.forward(req, resp);
	}
}

 

 

 

 

다형성(Polymorphism)

  • OOP의 주요 특징 중 하나임
  • 부모가 같은 class동일한 Type으로 들어 갈 수 있음
  • 특정 Interface를 구현받은 class가 해당 Interface형태로 들어갈 수도 있음

Written by zer0box

 

  • Fire
package kr.co.web.model;

public class Fire extends Spell{

	@Override
	public String casting() {
		return "화염 " + super.casting();
	}
}

 

  • Ice
package kr.co.web.model;

public class Ice extends Spell{

	@Override
	public String casting() {
		return "얼음 " + super.casting();
	}	
}

 

  • Light
package kr.co.web.model;

public class Light extends Spell{

	@Override
	public String casting() {
		return "번개 " + super.casting();
	}	
}

 

  • Spell
package kr.co.web.model;

public class Spell {
	
	public String casting() {
		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="cast">
		<select name="element">
			<option value="fire">불속성</option>
			<option value="ice">얼음속성</option>
			<option value="light">번개속성</option>
		</select>
		<input type="submit" value="마법사용"/>
	</form>
	<h3>${msg}</h3>
</body>
<script></script>
</html>

 

  • MageController
    • 부모클래스인 Spell클래스를 객체화하여 변수에 자식클래스 객체를 넣음
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.Fire;
import kr.co.web.model.Ice;
import kr.co.web.model.Light;
import kr.co.web.model.Spell;

@WebServlet("/cast")
public class MageController extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {

		String param = req.getParameter("element");
		System.out.println(param);
		String msg = "";
		Spell spell = null;

		switch (param) {
		case "fire":
			spell = new Fire();			
			break;
			
		case "ice":
			spell = new Ice();
			break;
			
		case "light":
			spell = new Light();
			break;			
		}
		msg = spell.casting();
		System.out.println(msg);
		
		req.setAttribute("msg", msg);
		RequestDispatcher dis = req.getRequestDispatcher("index.jsp");
		dis.forward(req, resp);
	}
}

 

 

Polymorphism(다형성)의 장점

  • 부모를 상속받는 객체들을 담을 변수를 여러개 만들지 않아도 됨(부모클래스or인터페이스를 객체화하여 사용)
  • 부모객체 형태로 매개변수를 받아 들어오는 변수의 폭을 넓힐 수 있음(부모객체로 자식객체를 다 받을 수 있음)
  • 다형성은 상속관계 뿐 아니라 구현 관계에서도 동작 

 

  • Car(부모)
package kr.co.web.model;

public class Car {	
	public String run() {
		return " 자동차를 운전합니다.";
	}
}

 

  • Benz(자식)
package kr.co.web.model;

public class Benz extends Car {
	@Override
	public String run() {		
		return this.getClass().getSimpleName() + super.run();
	}
}

 

  • BMW(자식)
package kr.co.web.model;

public class BMW extends Car {
	@Override
	public String run() {		
		return this.getClass().getSimpleName() + super.run();
	}
}

 

  • Audi(자식)
package kr.co.web.model;

public class Audi extends Car {
	@Override
	public String run() {		
		return this.getClass().getSimpleName() + super.run();
	}
}

 

  • Ferrari(자식)
package kr.co.web.model;

public class Ferrari extends Car {
	@Override
	public String run() {		
		return this.getClass().getSimpleName() + super.run();
	}
}

 

  • Racer(Car를 매개변수로 받음)
    • Car를 상속받는 객체면 다 들어올 수 있음
    • 사용할 차량을 추가하고 싶다면 Car를 상속받는 객체만 추가하면 됨
package kr.co.web.model;

public class Racer {

//레이서 클래스에 드라이브 메서드를 선언하여 매개변수로 Car타입의 변수를 받도록 했습니다.
//매개변수로 올 수 있는 Car타입의 변수는 Car타입을 상속받는 자식객체인 benz,bmw,audi,ferrari입니다.
	public String drive(Car car) {	
		return car.run();
	}	
//Car 클래스를 이용하여 규격화하지 않고 각각의 차량 클래스를 구현할 경우
//차량이 추가될 때 마다 메서드를 추가해 오버로딩해주어야 해서 번거로움이 있기 때문에
//대형 프로젝트를 진행할 경우에는 하나의 타입으로 자식 객체들을 불러올 수 있기 때문에 다형성을 이용하는 것이 유용합니다.
}

 

  • 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속성을 통해 데이터를 전달할 서버를 "drive"로 지정해주었습니다.
	<form action="drive">  
		<select name="car">
			<option value="benz">BENZ</option>
			<option value="bmw">BMW</option>
			<option value="audi">AUDI</option>
			<option value="ferrari">FERRARI</option>
		</select>
		<input type="submit" value="운전"/>
	</form>
	<h3>${msg}</h3>
</body>
<script></script>
</html>

 

  • CarController
package kr.co.web.Carcontroller;

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.Audi;
import kr.co.web.model.BMW;
import kr.co.web.model.Benz;
import kr.co.web.model.Ferrari;
import kr.co.web.model.Racer;

//어노테이션 웹서블릿으로 url패턴을 드라이브로 매핑해주었습니다.
@WebServlet("/drive")
public class CarController extends HttpServlet {
//이 클래스는 HttpServlet을 상속받았고 
//파라매터 값을 get방식으로 받기 때문에 doget메서드를 오버라이드 해주었습니다.
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {
		
//인덱스에서 넘어오는 car라는 이름의 파라매터 값을 car변수를 선언해 담아주었습니다.	
		String car = req.getParameter("car"); 
		//System.out.println(car);

//레이서 클래스를 객체화하여 racer 변수에 담아주었고
		Racer racer = new Racer();
		
//인덱스로 보내 줄 값을 담기 위해 result 변수를 선언해주었습니다.		
		String result = null;

//car변수에 들어온 값이 문자열 benz와 동일할 경우
//racer객체의 드라이브 메서드에 car객체를 상속받는 benz를 객체화하여 매개변수로 넣어 실행시켜준 후
//반환값을 result 변수에 담아주었습니다.		
		if(car.equals("benz")) {
			result = racer.drive(new Benz());
		}else if(car.equals("bmw")) {
			result = racer.drive(new BMW());
		}else if(car.equals("audi")){
			result = racer.drive(new Audi());
		}else {
			result = racer.drive(new Ferrari());
		}
		
		//ystem.out.println(result);
		
		req.setAttribute("msg", result); //request객체에 msg라는 이름으로 result 값을 담아주었고
//dis라는 변수에 request객체의 getRequestDispatcher메서드를 이용하여 이동할 경로를 index.jsp로 지정해주었습니다.
		RequestDispatcher dis = req.getRequestDispatcher("index.jsp");
		dis.forward(req, resp);
		//forward함수를 통해 request 객체와 response 객체를 index.jsp로 보내주었습니다.
	}
}

 

 

 

Promotion & Casting

  • 묵시적 형변환(Promotion)  :  자식 클래스가 부모 클래스 형태로 들어가는 것
  • 명시적 형변환(Casting)  :  자식의 형태로 되돌아 가는 것

 

다형성의 단점

  • 부모형태의 변수에 들어가면 자식 고유의 기능쓸 수 없음
  • 고유기능을 사용하고 싶은 경우 casting을 통해 자식 형태로 되돌아 가야함(되돌아 갈 때 원형을 잘 찾아가야함)
  • 다형성을 사용하려면 오버라이딩한 메서드만 사용하는 것이 좋음