🐢 꼬부기 LV.1 | 개념•기초/💧물대포(핵심개념)

MVC 파트별 내용정리

서화 2025. 10. 26. 23:33

각 패키지의 역할

Client : 앱을 설치하고 실행함

Controller  :  모델과 뷰를 데려와서 조합하는 역할을 한다 멤버변수로 모델과 뷰를 가지며 생성자를 통해 초기화를 해야한다  여러 패키지를 사용할때 공개범위를 public으로 해야한다 뷰와 모델의 파트를 분배하고 입력값과 출력값을 확인한다

Model : 데이터베이스(DB)의 역할을 하며 데이터의 저장/검색/삭제/변경 등 데이터에 접근할수 있게한다

View : 사용자에게 정보를 보여주고, 사용자에게 정보를 입력받는다, 사용자와 제일 밀접한 관계를 가진다

각 파트별 역할

Model = M

ArrayList <>에 자료형을 적는형태로 데이터를 가진다 이때 제네릭에 DTO/VO라는 이름을 적으면 되는데 여기서 DTO와 VO는 자료형을 나타내는 클래스뒤에 붙이는 말로 VO (Value Object)는 시스템에서 데이터를 주고받을 목적으로 자료형화 시킨 클래스이다. (예: 웹툰 VO, 회원 VO)

DTO(Data Transfer Object)는 VO와 같은 개념으로, 데이터를 전달하는 객체를 의미하며, 회사마다 DTO 또는 VO를 사용한다

DTO는 DAO를 쌍으로 가지고 있는데 DAO는 Data Access Object로 하나의 모델을 나타낸다  만약 시스템에 물건(Item)을 다루는 기능이 추가되면, 물건 DTO 와 물건 DAO 가 추가로 생긴다.

DAO 메서드의 성격 분류 (CUD vs RU)

RU (Read/Update): select all , select one 등 데이터를 받아다가 보여주는 역할을 한다.

Select All: 두 개 이상의 정보가 나올 수 있는 상황에 사용하며, 반환 타입은 무조건 배열(ArrayList)이다.

Select One: 반환이 무조건 한 개일 때 사용하며 (예: 로그인), 반환 타입은 DTO로 고정이다.

CUD (Create/Update/Delete): DB에 변화(추가, 삭제, 변경)를 줄 수 있는 친구들이다.

반환 타입: DB 변화 시도는 실패할 수도 있으므로, 성공/실패 여부를 반환하는 Boolean이 아웃풋으로 적합하다.

기본 코드 원칙: 개발 중 오류 방지를 위해 기본 코드를 깔아둘 때에는 false 나 null 등 폐쇄적으로 깔아두는 것이 좋다.

데이터를 줄때 원본을 주면 원본에 에러가 생길수도 있으므로 복사본을 만들어서 줘야한다 복사본은 ArrayList<>를 사용해서 새로운 배열을 만들어 원래 데이터의 크기만큼 반복문을 돌면서 원본 데이터를 복사하여 새로 만든 배열에 추가한다 이렇게 추가된 데이터를 new PersonDTO를 사용하여 객체를 만들고 원본의 값을 넣어준다

이름과 종족의 정보를 변경할때  update 메서드를 이름따로 종족따로 만들경우 인자의 타입과 개수가 같아서 오버로딩을 할수 없다 오버로딩이란 함수의 기능이 다를때 이름을 중복정의 할수 있도록한것인데 현재 DAO는 메서드의 개수를 5개로 고정하는 경우가 많다 (inesrt/ update / delete / select All / select One )

따라서  update 이름/  update 타입 이런식으로 이름을 바꾸는 것은 안되고  하나의  update 메서드에서 처리해 코드의 응집도를 높여야된다  찾는 부분을 번호로 변경하고 못찾으면 거짓을 반환하고 종료한다 찾았으면 그에 따른 조건을 수행하면된다

여기서 인자를 추가할수 있는데 바로 분기판단용 값인 condition과 변경할 내용인 content다 

변경할 대상의 이름이나 종족을 content 로 변경할수 있고 문자열을 비교할때는 equals를 사용한다

이름으로 주민검색추가시 select All 에 해당한다 여기서 select All 의 기능이 전체출력과 이름검색이 되므로 condition 과 검색내용(Key)을 인자로 받아야하는데 인자를 늘리면 컨트롤러에서 에러가 발생한다

이문제는 코드의 결합도가 높다는 증거이고 유지보수성이 낮다  여기까지가 MVC의 레벨 1단계

이 문제를 해결하려면 기존에 select One 은 인자를 숫자로 받았는데 PersonDTO의 personDTO로 바꾸고 inesr의 인자는 숫자와 문자였는데 똑같이 PersonDTO의 personDTO로 바꿔준다 

이렇게 만들면 메서드의 인자가 한개든 두개든 세개든 모든 정보를 한보따리에 싸서 주고받는 형태가 된다 즉 모든 객체의 인자를 PersonDTO로 통일한다 이러면 MVC의 2단계로 발전!

업데이트나 셀렉트올에서 분기판단용으로 사용되는 컨디션이나 검색어는 주민의 객체의 실제 데이터가 아니다 따라서 모델이나 컨드롤러에서 사용하려면 컨디션을 멤버변수에 추가해야한다 키도 만들어주면 해결가능!

DAO에 만들면 안된다 DTO에 만들어야된다 DAO에서는 샘플데이터 추가 가능하다 (VO는 실제 객체와 유사하게 코드가 퓨어할때 많이 사용됨 )

여기서 부터 (레벨2)부터는 생성자의 인자를 많이 받아야해서 코드가 복잡해진다 그래서 인자가 있는 생성자는 쓰지 않고 기본생성자만 사용해서 필요한 정보는 세터를 사용해 가져올수 있다

이제 검색을 위한 설정을 했고 검색을 하기위해 컨디션을 사용해서 분기처리를 하고 데이터를 전체돌면서 현재 보고있는 데이터가 검색한 데이터를 포함(문자열이니까 contains를 사용)하는지 확인하고 맞다면 복사한 데이터를 새로만든 객체에 추가한다

검색시 전체 데이터를 돌면서 모든 종족의 데이터를 반환하면 햄스터가 2마리일 경우 모두 출력된다 이러면 이제 사용자는 뷰파느에게 문제가 있다고 생각하지만 사실은 모델(DB)에 문제가 있는 경우이다 이럴때 검색어의 중복을 제거해줘야 한다

일단 기존배열에 해당타입이 없는지 먼저 체크해줘야한다 hsatype을 사용하면 확인할수 있다 이 hastype은 DAO에만 있으면 되므로 private로 선언해준다 hasType은 특정타입이 있는지 없는지를 체크해주기 때문에 boolean을 사용한다 다음 리턴값을 정해준다

View = V

사용자에게 정보를 받고 ,사용자에게 정보를 보여주는 역할을 한다 사용자에게 입력을 받아야하기때문에 스캐너는 공유자원으로 만들어야한다 (스태틱 사용하기) 사용자에게 보여줘야하는 필요한 메서드를 만든다 유효성 검사도 뷰파트에 해당한다 이때 트라이 캐치문을 사용하여 예외처리를 해줘야한다

주민의 정보를 변경해야할때 무엇을 바꿀지 알아야한다  이름이라면 새로만들지 않아도 되고 종족이라면 종족입력받기를 새로만들어야한다  여기서 뷰가 숫자를 컨트롤러에게 주고 이를 컨트롤러가 처리한다면 컨트롤러의 일이 2배가 되고 오류 발생시 컨트롤러가 돌려줘야하기때문에 코드 응집도 면에서 좋지 않다

더 좋은 방법은 뷰가 숫자를 보여주고 사용자가 선택하면 선택한 데이터 자체를 반환하는것이다 이렇게 하면 컨트롤러는 모델에게 전달하는 역할만 수행하므로 뷰가 타입을 결정하는 일을 스스로 처리하기 때문에 에 코드의 응집도가 높아진다 하나의 로직이 한곳에만 존재하는게 코드의 응집도를 높일수 있다

뷰가 종족목록(고양이,개구리, 햄스터)을 직접 보여주는 방법은 코드의 응집도가 낮고 결합도가 높은 방법이다 새로운 종족이 추가될때마다 코드를 직접 수정해야되고 뷰의 특성상 데이터 타입의 변화에 관심없어야한다 따라서 실제 데이터가 없는 종족을 보여주는 것은 비효율적이다

코드의 응집도를 높이려면 뷰가 모델에게 종족목록배열을 받은다음 그 목록을 사용자에게 보여준다 이렇게 하면 종족추가는 뷰가 몰라도 되는 일이고 만약에 프로젝트의 사이즈가 크다면 효율적이다

Controller = C

뷰와 모델에서 만든 코드들을 조합한다 이때 PK값은 시스템이 결정하는것이므로 컨트롤러에서 만들어야한다

주민의 정보를 변경할때 뷰에게 무엇을 바꿀지에 대한 입력값을 받아야한다 입력값에 따라 분기처리를 해주고 필요정보를 수집한다

모델에게서 업데이트 메서드의 인자인 숫자와 컨디션(이름or종족 변경),콘텐트(새이름/새종족)을 가져온다 실패시 로그를 남겨두면 원인을 파악하기 쉽다

수행결과에 따라서 뷰에게 성공,실패 여부를 출력요청한다 

인자명을 모두 PersonDTO로 맞췃기 때문에 컨트롤러가 모델에게 데이터를 요청할때마다 필요한 정보를 셋터에 담아서 포장한뒤에 전달해야한다 그때그때 필요한 정보가 달라서 기본생성자를 쓰고 필요한 정보만 세터로 설정하는것이 효율적이다 주민의 새로운 특성이 추가되도 인자목록이 바뀌지 않아서 다른 파트에 영향이없다

뷰에게 검색어를 입력받는다 PersonDTO객체를 만들고  컨디션을 이름으로 하고 검색어를 입력받은 키워드로 한다 모델에게 DTO를 담아서 보내고 반환된 목록을 뷰에게 출력요청한다

이름 검색 기능 추가후 실행하면 NullPointerException(NPE) 에러가 생긴다 Null = 데이터가 없다 즉 코드를 실행할 주어가 없는 상태로 셀렉트올의 주어인 컨디션의 조건이 없어서 생기는 문제인데 해결방법은 컨디션의 조건을 전체출력으로 설정해주면 된다 

컨트롤러는 모델에게 데이터를 받아올때 한개인지 여러개인지를 고민해봐야한다