재밌고 어려운 IT를 이해해보자~!
DTO (Data Transfer Object) DAO (Data Access Object) 본문
DTO
DB의 data에 접근하기 위한 객체로 실제로 DB에 접근하는 객체이다. ex)Student Class
JAVA는 2개이상의 값을 특히 return 할수없기때문에, 여러개의 값을 들고다닐목적으로 만든 클래스의 객체다. 이런 뜻!
DAO, VO(Value Object)
이런 DTO들을 CRUD해주는 클래스가 있다. ex) StudentModel
JAVA에서 DB와 연결이 되는 부분을 담당하는 클래스의 객체다. 이런 뜻!
DTO 와 VO의 차이
DTO - 데이터를 계층간 교환(Transfer)하는데 의미가 있음.
VO - 읽기만 가능한 read-only 속성을 가진 객체. 즉, setter가 없다.
각 DTO 마다 DAO가 꼭 하나씩은 있어야하며.
DAO는 default로 5개의 메서드를 갖는다.
insert,update,delete,selectAll,selectOne
boolean insert(DTO dto) 입력
boolean update(DTO dto) 변경
boolean delete(DTO dto) 삭제
ArrayList<DTO> selectAll(DTO dto) -> View에게 데이터를 전체데이터 전달하기 위한 메서드
return 전체 리스트
DTO selectOne(DTO dto)
return 리스트 중 한개.
스캐너사용시 팁 *
스캐너 전역변수는 좀 무겁다. 어차피 싱글톤을 유지하고 있음.
싱글톤(Singleton)이란 ?
싱글톤 패턴의 정의는 단순하다. 객체의 인스턴스가 오직 1개만 생성되는 패턴을 의미한다.
다음 Update 코드를 보자.
else if(action==4) {
int num=view.inputNum();
int score=view.inputScore();
boolean flag=model.update(num, score);
if(flag) {
view.printTrue();
}
else {
view.printFalse();
}
}
update 메서드에서는
PK와 새로운 점수를 받아 점수를 변경할 수도 있고
PK와 새로운 이름을 받아 이름을 변경할 수도 있다. 이때 오버로딩을 해서
어떤걸 입력 받았느냐에 따라서 메서드를 알아서 호출 하도록 할 수 있지만, 그렇게 할 경우
변경점이 있을때 모든 오버로딩된 메서드를 변경해줘야한다.
즉,
update() 메서드 오버로딩으로 해결하면, 기능변경시 실수가 자주 발생하기때문에
현업에서 사용되지않는 방법이다.
메서드를 오버로딩하여 여러개를 작성하면 응집도가 낮아짐 (같은 기능의 코드가 여러개)
유지보수에 불리한 코드.
또한 오버로딩을 사용하면
높은 응집도
하나의 기능을 하나의 메서드에서 처리할 수 있게 코드를 구성해야한다.
높은 결합도
코드에 변경사항이 발생했을때, 함께 바꿔야하는 코드가 많은 경우를 의미함.
따라서!
DAO의 CRUD 메서드 시그니쳐 인자값을 DTO로 고정시키면
결합도가 낮아져 변경사항 발생시 한 코드만 바꾸면 되고,
응집도가 높아져 하나의 기능을 하나의 메서드에서 처리할 수 있어진다.
public boolean update(StudentDTO studentDTO) {
boolean flag=false;
int i;
for(i=0;i<datas.size();i++) {
if(datas.get(i).getNum()==studentDTO.getNum()) {
flag=true;
break;
}
}
if(!flag) {
return false;
}
if(studentDTO.getName() != null) { // name 인자에 값을 부여했다면, 변경을 하고싶었던것!
datas.get(i).setName(studentDTO.getName());
System.out.println("[로그] 이름변경");
}
else {
datas.get(i).setScore(studentDTO.getScore());
System.out.println("[로그] 점수변경");
}
return true;
}
StudentDTO studentDTO 객체 자체를 메서드의 메게변수로 받아 .연산자 (접근연산자)를 사용해 StudentDTO의 메서드에 접근해서 필요한 멤버변수를 받아온다!!!!!!
DTO, DAO 를 활용한 학생부 프로그램 (점수검색, 이름검색 추가)
view
package view;
import java.util.ArrayList;
import java.util.Scanner;
import model.StudentDTO;
public class StudentView {
private Scanner sc;
public StudentView() {
sc = new Scanner(System.in);
}
public void printMenu() {
System.out.println("학생부");
System.out.println("1. 추가");
System.out.println("2. 목록");
System.out.println("3. 검색");
System.out.println("4. 변경");
System.out.println("5. 삭제");
System.out.println("0. 종료");
}
public int inputAction() {
System.out.print("메뉴입력 >> ");
int action = sc.nextInt();
return action;
}
public String inputName() {
System.out.print("이름입력 >> ");
String name = sc.next();
return name;
}
public int inputScore() {
System.out.print("점수입력 >> ");
int score = sc.nextInt();
return score;
}
public int inputNum() {
System.out.print("번호입력 >> ");
int num = sc.nextInt();
return num;
}
public void printTrue() {
System.out.println("기능 수행 완료 !");
}
public void printFalse() {
System.out.println("기능 수행 실패 ...");
}
public void printDatas(ArrayList<StudentDTO> datas) {
for (StudentDTO data : datas) {
System.out.println(data);
}
}
public void printData(StudentDTO data) {
System.out.println("현재 출력된 학생");
System.out.println(" ▼▼▼");
System.out.println(data);
}
public void printUpdateMenu() {
System.out.println("===변경중...===");
System.out.println("1. 성적변경");
System.out.println("2. 이름변경");
}
public void printSearchMenu() {
System.out.println("===검색중...===");
System.out.println("1. 점수검색");
System.out.println("2. PK검색");
System.out.println("3. 이름검색");
}
}
Model
StudentDTO
package model;
public class StudentDTO {
private int num; // PK
private String name;
private int score;
public StudentDTO(int num,String name,int score) {
this.num=num;
this.name=name;
this.score=score;
}
private String searchCondition; // 검색조건을 확인하기위한 용도
// "학생 데이터"와는 무관하기때문에,
// 생성자에서 초기화 xxx
public int getNum() {
return num;
}
public String getSearchCondition() {
return searchCondition;
}
public void setSearchCondition(String searchCondition) {
this.searchCondition = searchCondition;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student [num=" + num + ", name=" + name + ", score=" + score + "]";
}
}
StudentDAO
package model;
import java.util.ArrayList;
public class StudentDAO {
private ArrayList<StudentDTO> datas; // DB의 역할
public StudentDAO() {
this.datas=new ArrayList<StudentDTO>();
this.datas.add(new StudentDTO(1001,"티모",50));
this.datas.add(new StudentDTO(1002,"아리",89));
}
public ArrayList<StudentDTO> selectAll(StudentDTO studentDTO){
if(studentDTO.getSearchCondition().equals("점수검색")) {
ArrayList<StudentDTO> datas=new ArrayList<StudentDTO>(); // 반환할 목록
for(int i=0;i<this.datas.size();i++) {
if(this.datas.get(i).getScore()>=studentDTO.getScore()) {
datas.add(this.datas.get(i));
}
}
return datas;
}
else if(studentDTO.getSearchCondition().equals("이름검색")) {
ArrayList<StudentDTO> datas = new ArrayList<StudentDTO>();
for(int i=0; i<this.datas.size(); i++) {
if(this.datas.get(i).getName().contains(studentDTO.getName())) {
datas.add(this.datas.get(i));
}
}
return datas;
}
else {
return this.datas; // 전체 목록==DB==학생부 그 자체
}
}
public StudentDTO selectOne(StudentDTO studentDTO) {
boolean flag=false;
int i;
for(i=0;i<datas.size();i++) {
if(datas.get(i).getNum()==studentDTO.getNum()) {
flag=true;
break;
}
}
if(!flag) {
return null;
}
return datas.get(i);
}
public boolean insert(StudentDTO studentDTO) {
this.datas.add(new StudentDTO(studentDTO.getNum(),studentDTO.getName(),studentDTO.getScore()));
return true;
}
public boolean update(StudentDTO studentDTO) {
boolean flag=false;
int i;
for(i=0;i<datas.size();i++) {
if(datas.get(i).getNum()==studentDTO.getNum()) {
flag=true;
break;
}
}
if(!flag) {
return false;
}
if(studentDTO.getName() != null) { // name 인자에 값을 부여했다면, 변경을 하고싶었던것!
datas.get(i).setName(studentDTO.getName());
System.out.println("[로그] 이름변경");
}
else {
datas.get(i).setScore(studentDTO.getScore());
System.out.println("[로그] 점수변경");
}
return true;
}
public boolean delete(StudentDTO studentDTO) {
boolean flag=false;
int i;
for(i=0;i<datas.size();i++) {
if(datas.get(i).getNum()==studentDTO.getNum()) {
flag=true;
break;
}
}
if(!flag) {
return false;
}
datas.remove(i);
return true;
}
}
Controller
package ctrl;
import java.util.ArrayList;
import model.StudentDTO;
import model.StudentDAO;
import view.StudentView;
public class StudentCtrl {
private StudentView view;
private StudentDAO model;
public StudentCtrl() {
this.view = new StudentView();
this.model = new StudentDAO();
}
public void startApp() {
int PK = 1003;
while (true) {
view.printMenu();
int action = view.inputAction();
if (action == 0) {
break;
} else if (action == 1) {
String name = view.inputName();
int score = view.inputScore();
StudentDTO studentDTO = new StudentDTO(PK++, name, score);
boolean flag = model.insert(studentDTO);
if (flag) {
view.printTrue();
} else {
view.printFalse();
}
} else if (action == 2) {
StudentDTO studentDTO = new StudentDTO(0, null, 0);
studentDTO.setSearchCondition("전체 목록 출력");
ArrayList<StudentDTO> datas = model.selectAll(studentDTO);
view.printDatas(datas);
} else if (action == 3) {
view.printSearchMenu();
action = view.inputAction();
if (action == 1) {
int score = view.inputScore();
StudentDTO studentDTO = new StudentDTO(0, null, score);
studentDTO.setSearchCondition("점수검색");
ArrayList<StudentDTO> datas = model.selectAll(studentDTO);
view.printDatas(datas);
}
else if (action == 2) {
int num = view.inputNum();
StudentDTO studentDTO = new StudentDTO(num, null, 0);
studentDTO.setSearchCondition("PK검색");
StudentDTO data = model.selectOne(studentDTO);
if (data == null) {
view.printFalse();
continue;
}
view.printData(data);
}
else if (action == 3) {
String name = view.inputName();
StudentDTO studentDTO = new StudentDTO(0, name, 0);
studentDTO.setSearchCondition("이름검색");
ArrayList<StudentDTO> datas = model.selectAll(studentDTO);
view.printDatas(datas);
}
} else if (action == 4) {
view.printUpdateMenu();
action = view.inputAction();
boolean flag;
int num = view.inputNum();
if (action == 1) {
int score = view.inputScore();
StudentDTO studentDTO = new StudentDTO(num, null, score);
flag = model.update(studentDTO);
} else {
String name = view.inputName();
StudentDTO studentDTO = new StudentDTO(num, name, 0);
flag = model.update(studentDTO);
}
if (flag) {
view.printTrue();
} else {
view.printFalse();
}
} else if (action == 5) {
int num = view.inputNum();
StudentDTO studentDTO = new StudentDTO(num, null, 0);
boolean flag = model.delete(studentDTO);
if (flag) {
view.printTrue();
} else {
view.printFalse();
}
} else if (action == 6) {
}
}
}
}
Client
package client;
import ctrl.StudentCtrl;
public class Test {
public static void main(String[] args) {
StudentCtrl app=new StudentCtrl(); // 설치
app.startApp(); // 실행
}
}
TIPs
StudentDTO studentDTO 객체변수를 클래스에 선언 안하는 이유 -> 나중에 스프링에서 클래스명과 객체변수명을 같이 써준다. 미리 습관들여놓기
Scanner 타입에 static을 써줄이유는 없으며..? (클래스 호출시 바로생기기 때문에 정적메모리 낭비!! 무겁다, 한 객체와 무관하며 모든객체의 공유자원이된다.)
Scanner타입 객체 sc를 생성자 안에서 초기화 한 이유는 나중에 스프링 에서 쓰이느 것 같다!
생성자 주입은 생성자의 호출 시점에 1회 호출 되는 것이 보장된다. 그렇기 때문에 주입받은 객체가 변하지 않거나, 반드시 객체의 주입이 필요한 경우에 강제하기 위해 사용할 수 있다. 또한 Spring 프레임워크에서는 생성자 주입을 적극 지원하고 있기 때문에, 생성자가 1개만 있을 경우에 @Autowired를 생략해도 주입이 가능하도록 편의성을 제공하고 있다!
'코리아IT핀테크과정' 카테고리의 다른 글
MVC Pattern Practice 2 (0) | 2023.12.14 |
---|---|
MVC Pattern Practice 1 (0) | 2023.12.13 |
MVC design pattern (0) | 2023.12.12 |
컬렉션 프레임워크 (Collection Framework) (2) | 2023.12.07 |
추상클래스 (abstract class), 인터페이스 (Interface) (2) | 2023.12.06 |