updateTodo 맨 밑에 추가하기
titleInput.style["display"] = "";

titleInput 숨김으로 시작
주석 풀기

var titleInput = document.querySelector("#x-title-input");
titleInput.style["display"] = "none";

변경 취소 버튼

Todo 편집 취소 버튼 추가

button 종료태그 넣기

취소 버튼 추가하기

<button type="button" onclick="cancelTodo(${i})">취소</button>

취소 버튼이 처음에 보이면 안 됨
편집 상태일 때

인라인 스타일은 우선순위 1위

<button type="button" onclick="cancelTodo(${i})" style="display:none;">취소</button>

버튼에 아이디 부여

<button id="x-update-btn-${i}" type="button" onclick="updateTodo(${i})">변경</button>

변경을 누르면 인풋 박스가 생기고 변경 버튼이 사라지고 취소 버튼이 보여야 됨

태그를 찾는 방식 정리

tr을 찾는 걸로 바꾼다
자신이 속한 tr을 찾는 거
변경 버튼을 눌렀을 때 몇 번을 눌렀는지 알 수 있으니까 tr에 index를 붙인다

<td><span class="todo-title" ${titleTdOption}>${todoList[i].title}</span></td>
var titleSpan = document.querySelector(`tr[data-no="${no}"] .todo-title`);

td가 부모로부터 두 번째 자식

var titleSpan = document.querySelector(`tr[data-no="${no}"] > td.todo-title > span`);
var no = titleInput.parentNode.parentNode.getAttribute("data-no");

absolute로 공중부양 시켜서 위에 띄우는 경우가 있음
그런 경우에는 부모가 td가 아님

// updateTodo
titleInput.setAttribute("data-no", no);

Esc 키 27번

   if (e.keyCode == 27) { // ESC 키를 눌러 편집을 취소한다면
     titleSpan.style["display"] = "";
     titleInput.style["display"] = "none";
     document.body.appendChild(titleInput);
   }

5단계 - Todo 입력 폼을 목록 화면에 합친다.

목록 상단에 입력 폼을 추가한다. 키 이벤트 리스너를 추가한다.

입력 후 엔터 키를 누르면 목록에 추가한다. 서버 REST API 연동

  document.querySelector("#x-todo-input").onkeyup = function(e) {
    if (e.keyCode == 27) {
      e.target.value = "";
    } else if (e.keyCode == 13) {
      if (e.target.value == "") {
        window.alert("필수 입력 항목이 비어 있습니다.");
        return;
      }
      fetch(`/todo/add?title=${e.target.value}`)
        .then(function(response) {
          return response.text();
        })
        .then(function(text) {
          console.log(text);
          location.reload();
        });
    }
  };

목록을 가져온 다음에 커서를 인풋 박스에 두기

document.querySelector("#x-todo-input").focus();

User Experience : 사용자 편의를 고려한 디자인

다형성의 활용: 다형적 변수의 특징

90-MyList프로젝트1 / 25 페이지

배열의 타입이 다르면 코드도 변경해야 한다
배열의 타입이 다르면 ArrayList 클래스의 코드도 변경해야 한다.

이런 문제점을 해결하고자 한다.

만약 배열의 타입이 같다면 코드 변경을 최소화할 수 있다

여러 타입의 객체 주소를 받을 수 있는 배열은?

① Object 레퍼런스는 모든 타입의 객체 주소를 담을 수 있다.

② Object로 바꾸는 대신 이 배열을 사용하는 측에서 형변환을 처리해야 한다.

③ 같은 타입의 배열이기 때문에 별도의 코드 변경 최소화!

기존의 ArrayList의 레퍼런스 배열을 Object[] 타입으로 변경한다.

다형적 변수

Object 타입

Object obj = new Object();
Object obj = new Contact();
Object obj = new Todo();

그것을 가리키는 통상적인 용어
저거요
Object 타입이 저거라는 거

다형적 변수와 타입 계층도

90-MyList프로젝트1 / 28 페이지

클래스(분류)

하위 타입의 객체를 가리킬 수 있다

하위 타입의 객체 주소를 저장할 수 있다

무생물 타입의 레퍼런스는 하위 타입 객체 주소를 담을 수 있다
생물이라는 레퍼런스는 하위에 있는 모든 객체의 주소를 담을 수 있다
그 객체를 찾아갈 수 있다는 건 가리키고 있다는 거

Object

자바의 최상위 클래스 Object

90-MyList프로젝트1 / 29 페이지

다형적 변수 : 하위 타입의 객체를 가리킬 수 있다 (주소를 저장할 수 있다)

Object는 최상위 클래스

Contact, Todo는 Object의 서브 타입이다.

상위 분류를 가리킬 때 화살표로 가리킨다

하위 분류는 상위 분류를 못 가리킨다

super type = parent
sub type = child

class Contact extends Object {

}

1단계

static Object[] list = new Object[5];

add()의 파라미터 타입 변경

  static void add(Object obj) {
    if (size == list.length) {   // 배열이 꽉 찼다면,
      list = grow(); // 메서드 이름에서 해당 코드에 대한 설명을 짐작할 수 있다.
    }
    list[size++] = obj;
  }

toArray()의 리턴 타입 변경

  static Object[] toArray() {
    Object[] arr = new Object[size]; // 배열에 저장된 값만 복사할 새 배열을 만든다.
    for (int i = 0; i < size; i++) {
      arr[i] = list[i]; // 전에 배열에서 값이 들어 있는 항목만 복사한다.
    }
    return arr; // 복사한 항목들을 담고 있는 새 배열을 리턴한다.
  }

grow()의 리턴 타입 변경

  static Object[] grow() {
    Object[] arr = new Object[newLength()];
    copy(list, arr);
    return arr;
  }

newLength() 변경

  static int newLength() {
    return list.length + (list.length >> 1);
  }
  static void copy(Object[] source, Object[] target) {
    // 개발자가 잘못 사용할 것을 대비하여 다음 코드를 추가한다.
    // 즉 target 배열이 source 배열보다 작을 경우 target 배열 크기만큼만 복사한다.
    int length = source.length;
    if (target.length < source.length) {
      length = target.length;
    }
    for (int i = 0; i < length; i++) {
      target[i] = source[i];
    }
  }

remove()

  static Object remove(int index) {
    Object old = list[index];
    for (int i = index + 1; i < size; i++) {
      list[i-1] = list[i]; // 한 칸씩 앞으로 당긴다
    }
    size--;
    return old;
  }

Object 객체 주소를 리턴할 수도 있지만 하위 클래스 중에서 하나를 리턴할 수도 있다는 거

  static Object set(int index, Object obj) {
    if (index < 0 || index >= size) {   // 값이 저장된 위치가 무효한 인덱스라면
      return null;
    }
    Object old = list[index];
    list[index] = list;
    return old;
  }

remove를 손코딩
배열을 앞으로 당기는 걸 할 수 있는지

혼자서 안 보고 짤 수 있을 정도로 이해해야 됨

  @RequestMapping("/contact/get")
  public Object get(String email) {
    int index = ArrayList.indexOf(email);
    if (index == -1) {
      return "";
    } 

    return ArrayList.list[index];

  }

indexOf 옮기기

ArrayList의 배열 타입 변경

90-MyList프로젝트1 / 30 페이지

ContactController
클라이언트의 요청을 처리하는 메서드들이 들어 있다.

ArrayList
배열을 다루는 메서드 및 변수들이 들어 있다.

indexOf()를 ContactController로 이동

why?
indexOf()는 이메일을 가지고 배열의 항목을 찾는다.
indexOf() 메서드로 모든 타입에 대해 사용할 수 없고 Contact를 다룰 때만 사용한다. 그래서 그 역할을 수행하는 클래스로 옮긴 것이다.

Object[]
예전과 다르게 특정 타입의 배열을 다루는 것이 아니라 모든 타입의 배열을 다룬다.
즉 ArrayList Contact 뿐만 아니라 다양한 타입의 목록을 다루도록 변경했기 때문에 indexOf()를 다른 클래스로 옮긴 것이다.

역할이 바뀌면 바뀐 역할에 따라서 메서드가 옮겨지기도 한다.

절대 안 바뀌는 게 아니라 클래스 역할이 바뀌면 이동하거나
이런 것들 하는 게 객체 지향 프로그래밍

역할이 바뀜
지금 ArrayList는 어떤 타입의 배열도 다 다룰 수 있음

Todo에는 email이 없음
email은 Contact 라는 타입에만 있는 거

그럼 indexOf()가 ArrayList에 존재하는 건 말이 안 됨

리팩토링 기법 중에서 '메서드 이동' (Move Method)
객체 간의 기능 이동 - '메서드 이동' (Move Method)
리팩토링 → 이해하기 쉽도록 코드를 정리하는 거

Contact contact = (Contact) ArrayList.list[i];

컴파일러 입장에서는 모름
주소를 Contact에 담으라고 하니까 어이가 없는 거
그 주소가 Contact인지 어떻게 알고 담으라는 거냐
Todo 객체가 들어 있을 수도 있잖아
컴파일러 입장에서는 그 시도 자체가 잘못 된 거

Object obj = new Contact();

Contact r = obj; // 에러

컴파일러 속였다고 끝나는 거 아님
JVM을 속일 순 없음
실제로 괄호 안에 적은 타입이 변수에 들어 있어야 됨

ArrayList2.list[index].done = done;
list는 Object 타입
Object에는 done이라는 속성이 없다!

((Todo) ArrayList2.list[index]).done = done;
Todo 라고 했는데 Todo가 아니라 Contact가 들어 있으면 어떡해?
JVM은 명령어를 실행할 때마다 일일이 검사한다
JVM에서는 검사하기 때문에 그때 에러난다
JVM을 속일 방법은 없다

한 번 밖에 안 쓰는 변수를 만드는 건 낭비

레퍼런스 배열의 타입을 Object로 변경하니까 ArrayList를 복사했을 때 변경할 게 없다

다형적 변수

90-MyList프로젝트1 / 31 페이지

동물 obj;
obj = O ← 동물 객체 또는 그 하위 분류의 객체를 저장할 수 있다.

X obj = O; ← X 객체 주소나 X의 하위 타입 객체들의 주소가 올 수 있다.

메서드 파라미터가 클래스 이름이면 타입을 본다

04. 다형성의 활용 : 다형적 변수의 특징

90-MyList프로젝트1 / 32 페이지

컴퓨터에 있는 메모리 포함
메모리만 떼서 사용할 수 있음

TodoController - ArrayList2 - Object[]

BoardController - ArrayList3 - Object[]

클래스 관계

90-MyList프로젝트1 / 33 페이지

의사소통 하려고 만든 건데

UML, 실전에서는 이것만 쓴다
https://book.naver.com/bookdb/book_detail.nhn?bid=6439362

인스턴스 변수와 인스턴스 메소드

1단계 - 게시글 요청을 처리할 REST API를 만든다.

0개의 댓글