6주차 - 4) Java 2

변현섭·2023년 6월 12일
1

4th UMC Server-Spring Study

목록 보기
20/30

Ⅲ. 보충 설명

1. SOLID 원칙

① SRP(Single Responsibility Principle)

  • 단일 책임 원칙
  • 한 클래스는 하나의 책임만 가짐.
  • 변경에 대한 파급 효과가 적을수록 좋은 설계임.

② OCP(Open/Closed Principle)

  • 개방-폐쇄 원칙
  • 소프트웨어는 확장에는 열려있고, 변경에는 닫혀있어야 함.
  • 다형성을 활용하여 인터페이스에 대한 구현 클래스를 추가함으로써 새 기능을 구현함.
    (구현 클래스를 바꾸는 과정에서 코드를 변경하는 것도 OCP위배에 해당)

③ LSP(Liskov Substitution Principle)

  • 리스코프 치환 원칙
  • 객체는 프로그램의 정확성을 깨뜨리지 않는 하위 타입의 인스턴스로 바꿀 수 있어야 함.
  • 구현체를 믿고 사용하기 위한 원칙으로, 단순히 컴파일만 된다고 해서 잘 만든 코드가 아님을 의미.
  • 일례로 자동차의 브레이크와 엑셀의 위치를 바꿔 놓는 등의 설계가 리스코프 치환 원칙을 위배한다고 할 수 있음.

④ ISP(Interface Segreation Principle)

  • 인터페이스 분리 원칙
  • 특정 클라이언트에 대한 세부 인터페이스가 단일 범용 인터페이스보다 좋음.
  • 인터페이스의 명확성과 대체 가능성 향상.

⑤ DIP(Dependency Inversion Principle)

  • 의존관계 역전 원칙
  • 구체화가 아닌 추상화에 의존해야 함(즉, 구현 클래스가 아닌 인터페이스에 의존해야함).
  • 일반적으로는 인터페이스와 구현 클래스에 동시에 의존하므로, DIP가 위반됨.
    따라서 다형성만으로는 OCP, DIP를 준수할 수 없다. 이를 지키는 방법은 차후 프로그래밍을 하면서 알게 될 것이다.

2. 디자인 패턴

① 어댑터 패턴

  • 호출당하는 쪽의 메서드가 호출하는 쪽의 코드에 대응되도록, 중간에 변환기를 통해 호출하는 패턴
  • 서로 다른 두 인터페이스 사이에 통신이 가능하게 하는 것.
  • JDBC, JRE가 여기에 속함.

② 프록시 패턴

  • 제어 흐름을 조정하기 위한 목적으로 중간에 대리자(proxy)를 두는 패턴
  • 프록시 패턴은 OCP와 DIP가 적용된 설계 패턴임.
  • 스프링 AOP에서 사용하는 패턴으로, 객체를 실제로 부르는 대신, 프록시 객체를 부르고 나중에 프록시 객체가 실제 객체를 호출함.

③ 데코레이터 패턴

  • 메서드 호출의 반환 값에 변화를 주기 위해 중간에 장식자를 두는 패턴
  • 상속을 통해 확장하는 형태로 활용

④ 싱글톤(SingleTon) 패턴

  • 클래스의 인스턴스, 즉 객체를 하나만 만들어 사용하는 패턴
  • 서버와의 Socket Connection과 스프링 Bean에서 사용하는 패턴이자 꼭히 익혀두어야 하는 주요한 패턴.
  • new를 실행할 수 없도록 생성자의 접근 제어자를 private으로 지정. 유일한 단일 객체 반환을 위한 정적 메서드인 getInstance()와 유일한 단일 객체를 참조할 정적 참조 변수가 필요함.
  • 기존에 생성된 인스턴스를 반복적으로 활용한다는 점에서 속도가 빠르고, 전역 인스턴스(static)라는 점에서 여러 클래스에서 접근 가능함.
  • 자식 클래스 생성이 불가하고, 테스트가 어려우며, 구체 클래스에 의존해야 한다는 것은 단점임.

③ 옵저버 패턴

  • 변화가 일어났을 때, 미리 등록된 다른 클래스에 통보해주는 패턴
  • Event Listener에 사용됨.

④ 파사드(Facade) 패턴

  • 여러 개의 객체와 실제 사용하는 서브 객체 사이에 복잡한 의존관계가 있을 때, 중간에 facade 객체를 두어 여기서 제공하는 interface의 기능을 사용하는 방식
    이외에도 전략 패턴, 템플릿 메서드 패턴, 팩토리 메서드 패턴, 템플릿 콜백 패턴 등 패턴은 매우 다양하다. 하지만, 싱글톤 패턴 외의 다른 패턴을 상세히 알아야 할 필요는 없다.

3. Java 입출력

1) 표준 입출력과 파일 입출력

자바는 표준 입출력 장치를 위해 System이라는 표준 입출력 클래스를 정의한다. java.lang 패키지에 포함되어 있으며 아래의 클래스 변수를 제공한다.

입출력 스트림은 자바가 자동 생성하므로 개발자가 별도로 생성하지 않아도 된다.
표준 입출력의 대상을 변경하는 것도 가능하다. 앞서 살펴본 세가지 입출력 스트림은 모두 콘솔을 대상으로 한다. System의 메서드를 활용하면 스트림의 대상을 다른 입출력 장치로 변경할 수 있다.

입출력 스트림을 사용하면 파일을 통한 입출력 작업도 수행할 수 있다. 하지만 입출력 작업 이외의 다른 작업은 수행할 수 없기 때문에 자바는 File클래스를 통해 아래의 기능을 제공한다.

2) 바이트 기반 입출력과 문자 기반 입출력

입출력은 쉽게 말해 한쪽에서 다른쪽으로 데이터를 전달하는 것이다. 이 때 입출력을 위한 데이터의 흐름을 스트림이라고 한다. 스트림은 연속적인 데이터의 흐름을 물에 비유해서 붙여진 이름인데, 물이 한쪽 방향으로만 흐르듯이 스틈 또한 단방향 통신만 가능하다. 그러므로 입력과 출력을 동시에 수행하기 위해선 입력스트림과 출력스트림, 총 2개의 스트림이 필요하다. 스트림은 FIFO 구조를 이룬다. 이러한 스트림에는 바이트 기반 스트림과 문자 기반 스트림이 있다.

바이트 기반 스트림(InputStream, OutputStream)은 바이트 단위로 데이터를 전송한다. 즉, 입출력의 단위가 1byte이다. InputStream클래스에서 제공하는 메서드는 아래와 같다.

참고로 read()의 반환타입이 byte가 아니라 int인 이유는 읽기에 실패한 경우 -1을 반환해야 하기 때문이다. OutputStream클래스의 메서드는 아래와 같다.

문자기반 스트림(Reader, Writer)은 바이트 기반의 스트림으로는 2byte 문자(자바는 문자를 2byte의 유니코드로 처리함)를 처리하기 어렵기 때문에 사용된다. 따라서 문자데이터를 입출력할 때는 문자 기반 스트림을 사용하는 것이 좋다.

스트림의 기능을 추가, 확장, 보완해주는 역할로 보조스트림도 있다. 그리고 보조스트림에는 바이트 기반 보조스트림과 문자기반 보조스트림이 있다.
문자열을 입력받는 코드를 생각해보자. 문자열을 입력받는 방법에는 두가지가 있는데, 첫번째는 Scanner를 이용하는 것이고, 두번째는 BufferReader를 이용하는 것이다. Scanner는 바이트기반 입력이고, BufferReader는 문자열 기반 입력이다.

Scanner방식이 BufferReader에 비해 코드가 간결하고, int, long, short, float, double, String을 nextInt(), nextLong(), nextShort(), nextFloat(), nextDouble(), nextLine()과 같은 함수로 모두 받을 수 있다.

반면 BufferReader는 오직 String형식의 값만 읽을 수 있기에 readLine()함수만 사용 가능하다. 다만, 그 외에 모든 점은 다 BufferReader가 좋다고 보면 된다. 메모리 용량도 효율적이고 멀티쓰레드 환경에서도 안전하며, 실행속도도 매우 빠르다. 형식은 아래의 예시를 참고하자.

profile
Java Spring, Android Kotlin, Node.js, ML/DL 개발을 공부하는 인하대학교 정보통신공학과 학생입니다.

0개의 댓글