개발자입니다
[비트캠프] 60일차(13주차2일) - Java(데코레이터, I/O stream), myapp-27~28 본문
[비트캠프] 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
'네이버클라우드 AIaaS 개발자 양성과정 1기 > Java' 카테고리의 다른 글
[비트캠프] 62일차(13주차4일) - Java(Client, Server 아키텍처), myapp-32-1~2 (0) | 2023.02.02 |
---|---|
[비트캠프] 61일차(13주차3일) - Java(네트워킹), myapp-29~32 (0) | 2023.02.01 |
[Java] 예제 소스 정리 - 파일 입출력 (0) | 2023.01.30 |
[비트캠프] 59일차(13주차1일) - Java(컬렉션 API, 파일 입출력), myapp-26 (0) | 2023.01.30 |
[비트캠프] 58일차(12주차3일) - Java(람다, 메서드 레퍼런스, 제네릭), myapp-24, 25 (0) | 2023.01.27 |