Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

개발자입니다

[비트캠프] 60일차(13주차2일) - Java(데코레이터, I/O stream), myapp-27~28 본문

네이버클라우드 AIaaS 개발자 양성과정 1기/Java

[비트캠프] 60일차(13주차2일) - Java(데코레이터, I/O stream), myapp-27~28

끈기JK 2023. 1. 31. 16:02

 

myapp

 

 

27. Decorator 설계 기법을 이용하여 기능 확장하기

 

### 27. Decorator 디자인 패턴을 이용하여 데이터를 바이트 배열로 입출력하는 기능을 캡슐화하기: DataInputStream/DataOutputStream 
- Primitive 타입과 String 타입의 값을 바이트 또는 바이트 배열로 가공하는 방법 
- GoF의 데코레이터 설계 기법의 이해

 

데이터를 DataOutputStream 의 writeByte(), writeShort() 사용하여 data를 byte[ ] 로 가공한다. data(int, String, boolean, ...) 이용해서 byte[ ] 생성한다. FileOutputStream 의 write() 사용해서 byte 또는 byte[ ] 로 변환해서 바이너리 파일 생성한다.

바이너리 파일을 FileInputStream 사용해서 byte 또는 byte[ ] 로 변환한다. DataInputStream 이 read() 사용해서 byte[ ] 를 data(int, String, boolean, ...) 로 byte[ ] 를 data 로 가공한다. readByte(), readShort() 사용해서 데이터로 바꾼다.

 

DataI/OStream 을 "Data Processing Stream Classes" = "Decorator" 라 한다. (필터역할)

FileI/OStream 을 "Data Sink Stream Classes" 라 한다.

 

 

public class BoardDao {

/* 아래 코드 수정 */

  public void save(String filename) {
    try (FileOutputStream out0 = new FileOutputStream(filename);
        DataOutputStream out = new DataOutputStream(out0)) {

      out.writeInt(list.size());

      for (Board b : list) {
        out.writeInt(b.getNo());
        out.writeUTF(b.getTitle());
        out.writeUTF(b.getContent());
        out.writeUTF(b.getPassword());
        out.writeInt(b.getViewCount());
        out.writeUTF(b.getCreatedDate());
      }

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void load(String filename) {
    if (list.size() > 0) {
      return;
    }

    try (FileInputStream in0 = new FileInputStream(filename);
        DataInputStream in = new DataInputStream(in0)) {

      int size = in.readInt();

      for (int i = 0; i < size; i++) {
        Board b = new Board();
        b.setNo(in.readInt());
        b.setTitle(in.readUTF());
        b.setContent(in.readUTF());
        b.setPassword(in.readUTF());
        b.setViewCount(in.readInt());
        b.setCreatedDate(in.readUTF());

        list.add(b);
      }

      if (list.size() > 0) {
        lastNo = list.get(list.size() - 1).getNo();
      }

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

public class TeacherDao {

/* 아래 코드 수정 */

  public void save(String filename) {
    try (FileOutputStream out0 = new FileOutputStream(filename);
        DataOutputStream out = new DataOutputStream(out0)) {

      out.writeInt(list.size());

      for (Teacher t : list) {
        out.writeInt(t.getNo());
        out.writeUTF(t.getName());
        out.writeUTF(t.getTel());
        out.writeUTF(t.getCreatedDate());
        out.writeUTF(t.getEmail());
        out.writeInt(t.getDegree());
        out.writeUTF(t.getSchool());
        out.writeUTF(t.getMajor());
        out.writeInt(t.getWage());
      }

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void load(String filename) {
    if (list.size() > 0) {
      return;
    }

    try (FileInputStream in0 = new FileInputStream(filename);
        DataInputStream in = new DataInputStream(in0)) {

      int size = in.readInt();

      for (int i = 0; i < size; i++) {
        Teacher t = new Teacher();
        t.setNo(in.readInt());
        t.setName(in.readUTF());
        t.setTel(in.readUTF());
        t.setCreatedDate(in.readUTF());
        t.setEmail(in.readUTF());
        t.setDegree(in.readInt());
        t.setSchool(in.readUTF());
        t.setMajor(in.readUTF());
        t.setWage(in.readInt());

        list.add(t);
      }

      if (list.size() > 0) {
        lastNo = list.get(list.size() - 1).getNo();
      }

    } catch (FileNotFoundException e) {
      System.out.println("데이터 파일이 존재하지 않습니다!");

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

 

public class StudentDao {

  public void save(String filename) {
    try (FileOutputStream out0 = new FileOutputStream(filename);
        DataOutputStream out = new DataOutputStream(out0)) {

      out.writeInt(list.size());

      for (Student s : list) {
        out.writeInt(s.getNo());
        out.writeUTF(s.getName());
        out.writeUTF(s.getTel());
        out.writeUTF(s.getCreatedDate());
        out.writeUTF(s.getPostNo());
        out.writeUTF(s.getBasicAddress());
        out.writeUTF(s.getDetailAddress());
        out.writeBoolean(s.isWorking());
        out.writeChar(s.getGender());
        out.writeByte(s.getLevel());
      }

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void load(String filename) {
    if (list.size() > 0) {
      return;
    }

    try (FileInputStream in0 = new FileInputStream(filename);
        DataInputStream in = new DataInputStream(in0)) {

      int size = in.readInt();

      for (int i = 0; i < size; i++) {
        Student s = new Student();
        s.setNo(in.readInt());
        s.setName(in.readUTF());
        s.setTel(in.readUTF());
        s.setCreatedDate(in.readUTF());
        s.setPostNo(in.readUTF());
        s.setBasicAddress(in.readUTF());
        s.setDetailAddress(in.readUTF());
        s.setWorking(in.readBoolean());
        s.setGender(in.readChar());
        s.setLevel(in.readByte());

        list.add(s);
      }

      if (list.size() > 0) {
        lastNo = list.get(list.size() - 1).getNo();
      }

    } catch (FileNotFoundException e) {
      System.out.println("데이터 파일이 존재하지 않습니다!");

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

 

 

 

Decorator Design Pattern 의 계층도 : I/O Stream

 

《component》InputStream 을 《concrete》FileInputStream, 《concrete》ByteArrayInputStream, 《concrete》PippedInputStream 이 상속한다. 《decorator》FilterInputStream 이 상속하며 부모 객체를 포함하기도 한다. 다른 객체에 기능을 덧붙인다. 생성자를 통해 다른 객체를 포함.

이를 상속하는 DataInputStream, BufferedInputStream 이 있다. 덧붙이는 기능으로 readInt(), readUTF(), readBoolean(),  ... 가 있다.

 

 

 

기능 확장법

 

① 상속

A 에 기능1(), 기능2() 있고 이를 B 가 상속한다. B는 기능3(), 기능4() 가 있고 기존 기능 변경한 기능1() 이 있다.

 

② 포함

B 는 기능3(), 기능1(), 기능2() 가 있다. B 가 A 를 사용하며 기능1(), 기능2() 를 위임한다.

방식은 class B 의 생성자 매개변수에 A 를 포함한다.

 

③ 데코레이터

부모 클래스 K 가 있고 자식 클래스 B, A, X, Y 가 있다. B 가 K 를 포함한다. 이를 decorator라 하며, 다른 형제·자손에게 기능을 덧붙이는 역할이다.

방식은 class B 의 생성자 매개변수에 K 를 포함하며, B 의 인스턴스 생성시 매개변수에 A, X, Y 인스턴스 생성할 수 있다.

 

 

 

데코레이터

 

K 의 Decorator 가 있고 자손으로 F1 ~ F4 가 있을 때 인스턴스 생성시 F3 call 에서 F2 call, A call 하는 방식으로 할 수 있다. 필터(데코레이터)를 붙였다가 뗏다가 자유롭게 할 수 있다.

 

 

 

28. 객체 직렬화

 

### 28. 인스턴스를 통째로 입출력하기(객체 직렬화): ObjectInputStream/ObjectOutputStream 
- 인스턴스 필드의 값을 통째로 입출력하는 방법

 

객체를 ObjectOutputStream 의 writeObject() 를 이용해 바이트 배열로 만든다. serialize(직렬화) = (marshalling) 이라 한다. 이를 FileOutputStream 의 write() 이용해 byte[ ] 을 파일로 만든다. bytes = 클래스 정보 + 필드 값 이 있다.

파일을 FileInputStream 의 read() 이용해 byte[ ] 로 만든다. 이를 ObjectInputStream 의 readObject() 이용해 객체로 만든다. deserialize(역직렬화) = (unmarshalling) 이라 한다.

이때 객체는 serialize 허용으로 설정되어 있어야 한다 = java.io.Serializable 인터페이스 구현. 객체에 implements 선언만 하면된다.

 

 

package bitcamp.myapp.dao;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import bitcamp.myapp.vo.Board;

public class BoardDao {

/* 아래 코드 수정 */

  public void save(String filename) {
    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename))) {
      out.writeObject(list);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @SuppressWarnings("unchecked")
  public void load(String filename) {
    if (list.size() > 0) {
      return;
    }

    try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename))) {

      list = (List<Board>) in.readObject();
      if (list.size() > 0) {
        lastNo = list.get(list.size() - 1).getNo();
      }

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

package bitcamp.myapp.dao;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import bitcamp.myapp.vo.Teacher;

public class TeacherDao {

/* 아래 코드 수정 */

  public void save(String filename) {
    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename))) {

      out.writeObject(list);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @SuppressWarnings("unchecked")
  public void load(String filename) {
    if (list.size() > 0) {
      return;
    }

    try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename))) {

      list = (List<Teacher>) in.readObject();
      if (list.size() > 0) {
        lastNo = list.get(list.size() - 1).getNo();
      }

    } catch (FileNotFoundException e) {
      System.out.println("데이터 파일이 존재하지 않습니다!");

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

 

package bitcamp.myapp.dao;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import bitcamp.myapp.vo.Student;

public class StudentDao {

  public void save(String filename) {
    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename))) {

      out.writeObject(list);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @SuppressWarnings("unchecked")
  public void load(String filename) {
    if (list.size() > 0) {
      return;
    }

    try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename))) {

      list = (List<Student>) in.readObject();
      if (list.size() > 0) {
        lastNo = list.get(list.size() - 1).getNo();
      }

    } catch (FileNotFoundException e) {
      System.out.println("데이터 파일이 존재하지 않습니다!");

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

 

 

package bitcamp.myapp.vo;

import java.util.Objects;

// Serializable 인터페이스
// - 객체를 자동으로 직렬화할 수 있도록 설정한다.
// - 따로 메서드를 구현할 필요는 없다.
// - 단지 직렬화를 활성화시키는 표시자 역할을 할 뿐이다.
//
public class Board implements java.io.Serializable {
  // 직렬화 데이터의 버전을 명시한다.
  // - 나중에 데이터를 읽을 때,
  //   이 버전을 보고 읽을 수 있는 데이터인지 아닌지 판단하는 용도로 사용한다.
  // - 누가 판단? ObjectInputStream 클래스!
  //
  private static final long serialVersionUID = 1L;
package bitcamp.myapp.vo;

import java.util.Objects;

public class Member implements java.io.Serializable {
  private static final long serialVersionUID = 1L;
package bitcamp.myapp.vo;

public class Teacher extends Member implements java.io.Serializable {
  private static final long serialVersionUID = 1L;
package bitcamp.myapp.vo;

public class Student extends Member implements java.io.Serializable {
  private static final long serialVersionUID = 1L;

 

 

 


 

 

조언

 

*

 

 

 


 

과제

 

학습

- com/eomcs/io/ex03~15