원지의 개발
article thumbnail
728x90

생성

JPA

  • EJB 엔티티빈(사용 어려움)이 등장 후 하이버네이트가 나왔고, 표준으로 JPA가 됨
  • JPA는 표준 인터페이스이고 구현체로 하이버네이트, EclipseLink 등이 있음

스프링

  • 로드 존슨
  • EJB의 문제점 지적 후 생긴 기술

스프링 프레임워크

  • 핵심 기술: 스프링 DI 컨테이너, AOP, 이벤트, 기타
  • 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크
  • 웹기술: 스프링 MVC, 스프링 WebFlux
  • 데이터 접근 기술: 트랜잭션, JDBC, ORM 지원, XML 지원
  • 기술 통합: 캐시, 이메일, 원격접근, 스케줄링
  • 테스트: 스프링 기반 테스트 지원
  • 언어: 코틀린, 그루비

스프링 부트

  • 스프링을 편하게 사용할 수 있도록 지원
  • 단독으로 실행할 수 있는 스프링 애플리케이션을 쉽게 생성 (톰캣 내장)
  • 손쉬운 빌드 구성을 위한 starter 종속성 제공 (AOP, Data-JPA 등 알아서 라이브러리 땡겨옴)
  • 스프링과 3rd party(외부) 라이브러리 자동 구성
  • 모니터링 해줌

객체 지향 프로그래밍

  • 역할(인터페이스)과 구현(구현한 클래스, 구현 객체)을 분리하면 유연해지며, 변경도 편리해짐
  • 객체는 협력이라는 관계부터 생각 (혼자 있는 객체는 X)
  • 클라이언트: 요청, 서버: 응답
  • 다형성: 클라리언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있음

실습 - 비즈니스 요구사항과 설계

  • 비즈니스 요구 사항 설계시 회원 저장소가 미정된 상태로 우선 개발 진행
  • 역할과 구현을 나눠서 인터페이스를 만들고, 구현체를 언제든지 갈아 끼울 수 있게 만들어야 함
  • 실습은 스프링 사용 없이 개발 진행

1. 회원 도메인

설계

1. 전체적인 도메인 그림

  • 역할로써 클라이언트 - 회원 서비스 - 회원 저장소로 분리
  • 그중에서 회원 저장소(역할)는 나중에 어떻게 될 지 모르기 때문에 인터페이스로 만들고, 우선 메모리 회원 저장소(컴퓨터 재부팅 시 삭제)로 구현해서 사용 하다가 확정되면 갈아 끼울 수 있게 만듦

2. 클래스 다이어그램

  • 정적
  • 멤버서비스 인터페이스(역할) 만든 후, 회원 서비스는 회원가입, 회원조회만 하니까 implements 받아서 구현하기

3. 객체 다이어그램

  • 동적 (실행했을 때 어떻게 되는지)
  • 애플리케이션을 띄워서 동적으로 객체들의 연관관계가 맺어지는 그림
  • 클래스 다이어그램으로 알 수 없는 부분 (예를 들어 저장소는 실행 후 동적으로 동작되기 때문에)이 있으므로 실제 실행되는 인스턴스의 설계

개발

  • 인터페이스와 구현체를 다른 패키지에 놓는 게 설계상 좋음
  • 등급은 Enum, 사용자(멤버)는 class로 만들기
  • 역할로 MemberRepository(인터페이스) 만들고 save 저장 기능, findById 조회 기능
  • implements 받아서 구현해야하는데 저장소이기 때문에 
private static Map<Long, Member> store = new HashMap<>();
//실무에서는 동시성 이슈로 ConcurrentHashMap 써야 함
  • 구현체가 없이 null 이면 터지므로 구현체로 MemoryMemberRepository 만들기

실행 및 테스트

package hello.core.member;

import static org.junit.jupiter.api.Assertions.*;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

class MemberServiceTest {

	MemberService memberService = new MemberServiceImpl();
	
	@Test
	void join() {
		//given
		Member member = new Member(1L, "memberA", Grade.Vip);
		
		//when
		memberService.join(member);
		Member findMember = memberService.findMember(1L);
		
		//then
		Assertions.assertThat(member).isEqualTo(findMember);
	}
}
package hello.core.member;

public class MemberApp {

	public static void main(String[] args) {
		MemberService memberService = new MemberServiceImpl();
		
		Member member = new Member(1L, "memberA", Grade.Vip);
		memberService.join(member);
		
		Member findMember = memberService.findMember(1L);
		
		//제대로 동작한다면 저장한 member == 찾은 findMember
		System.out.println(member);
		System.out.println(findMember);
	}
}
  • MemberApp 클래스는 순수 자바코드로 확인
  • 문제점
    MemberServiceImpl 클래스에서
    인터페이스(MemberRepository)는 의존하지만 구현체(MemoryMemberRepository)까지 의존하게 됨
    추상화, 구체화 둘 다에 의존 -> DIP 위반
  • org.assertj.core.api.Assertions는 메서드 체이닝 지원하기 때문에 문자와 숫자를 비교할 때도 가독성이 좋음
Method chaining 메서드 체이닝
: 하나의 객체에 대해 연속적으로 여러 메서드를 호출하는 것
체인내의 각 메서드는 이전 메서드를 기반으로 동작하고, 다음 메서드를 호출
동일한 객체 참조를 반복하지 않고도 동일한 객체에 대해 여러 어셔션 수행 가능
import static org.assertj.core.api.Assertions.assertThat;

public class ExampleTest {
    public void testExample() {
        String text = "안녕, 세계!";

        // 메서드 체이닝을 사용한 어서션
        assertThat(text)
            .isNotNull()
            .startsWith("안녕") //시작이 "안녕"인가?
            .endsWith("세계!") //끝이 "세계!"인가?
            .hasSize(8); //text 길이가 8인가?
    }
}

 

728x90
profile

원지의 개발

@원지다

250x250