본문 바로가기

프로그래밍/- Spring

[ 스프링 핵심 원리 이해2 ] 객체 지향 원리 적용 : 좋은 객체 지향 설계의 5가지 원칙의 적용 ~ 스프링으로 전환하기

 

 

좋은 객체 지향 설계의 5가지 원칙의 적용

 

 

 

➡️ SRP 단일 책임 원칙 : 한 클래스는 하나의 책임만 가져야 한다

  🔸클라이언트 객체는 직접 구현 객체를 생성, 연결, 실행하는 다양한 책임을 가지고 있었음

  🔸관심사 분리 >> AppConfig(구현 객체 생성, 연결) / 클라이언트 객체(실행)

 

 

➡️ DIP 의존 관계 역전 원칙 : 추상화에 의존해야지, 구체화의 의존하면 안된다

  🔸 클라이언트 코드가 DiscountPolicy 추상화 인터페이스에만 의존하도록 코드 변경

  🔸 AppConfig가 FixDiscountPolicy 객체 인스턴스를 대신 생성해서 의존관계를 주입

 

 

➡️ OCP : 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다

  🔸AppConfig가 의존 관계를 변경해서 클라이언트 코드에 주입하기 때문에 클라이언트 코드 변경x

  🔸소프트웨어 요소를 새롭게 확장해도 사용 영역의 변경은 닫혀 있다 (변경할 필요가 없다)

 

 

 

 

 

 

IoC, DI, 그리고 컨테이너

 

 

➡️ 제어의 역전 IoC(Inversion of Control)

  🔸기존 프로그램은 클라이언트 구현 객체가 스스로 서버 구현 객체를 생성, 연결, 실행했다 ( 프로그램의 제어 흐름을 스스로 조종했다)

  🔸AppConfig 등장 이후 구현 객체는 실행의 역할만 가지며 제어 흐름은 AppConfig가 가져간다. 구현 객체는 어떤 객체들이 실행될지 모른다.(단지 실행만)

  🔸프로그램에 대한 제어 흐름은 모두 AppConfig가 소유

  🔸이렇게 프로그램의 제어 흐름을 직접 제어하지 않고 외부에서 관리하는 것이 제어의 역전(IoC)

 

 

➡️ 프레임워크 vs 라이브러리

  🔸프레임워크 : 내가 작성한 코드를 프레임워크가 제어하고, 대신 실행 (ex : JUnit)

  🔸라이브러리 : 내가 작성한 코드가 직접 제어의 흐름을 담당 (ex : Json, XML등 변환 라이브러리 )

 

 

➡️ 의존관계 주입 DI(Dependency Injection)

  🔸정적인 클래스 의존관계 vs 실행 시점에 결정되는 동적인 객체(인스턴스) 의존관계

  🔸정적인 클래스 의존관계 : 실행하지 않아도 분석 가능. 실제 어떤 객체가 주입 될 지는 알 수 없음

 

  🔸 실행 시점에 결정되는 동적인 객체(인스턴스) 의존관계 : 애플리케이션 실행 시점 실제 의존 관계

 

  🔸 의존관계 주입 : 애플리케이션 실행 시점에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결되는 것

  🔸객체 인스턴스를 생성하고, 그 참조값을 전달해서 연결 >> 클라이언트 코드 변경 없이 인스턴스 변경 가능

  🔸정적인 클래스 의존관계를 변경하지 않고 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.

 

 

➡️ IoC 컨테이너, DI 컨테이너

  🔸AppConfig처럼 객체를 생성, 관리하며 의존관계를 연결해주는 것

  🔸( = 어샘블러(조립의 의미), 오브젝트 팩토리)

 

 

 

 

 

스프링으로 전환하기

 

 

 

➡️ ApplicationContext와 getBean메서드로 스프링컨테이너에 등록 후 사용

 

package hello.core;

import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MemberApp {
    public static void main(String[] args) {
        //AppConfig appConfig = new AppConfig();
        //MemberService memberService = appConfig.memberService();

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        //AppConfig에 있는 설정정보를 가지고 스프링 컨테이너에 넣어 관리하겠다.
        MemberService memberService = applicationContext.getBean("memberService", MemberService.class);


        Member member = new Member(1L, "memberA", Grade.VIP);
        memberService.join(member); //회원가입

        Member findMember = memberService.findMember(1L);
        System.out.println("member = " + member.getName());
        System.out.println("findMember = " + findMember.getName());
    }

}
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);

 

등록 후 실행 시 로그가 안보이는 경우 resources에 logback.xml파일 생성해 아래 코드 넣어주기❗

     (버전 업그레이드로 인해 불필요한 로그 숨김처리 되어있음)

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n</pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

 

 

 

 

➡️ 스프링 컨테이너

  🔸ApplicationContext를 스프링 컨테이너라고 한다

  🔸기존에는 개발자가 직접 객체를 생성하고 DI를 했지만, 현재는 스프링 컨테이너를 통해 사용

  🔸스프링 컨테이너는 @Configuration이 붙은 설정 정보를 사용

  🔸@Bean이라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록 >> 이 객체를 스프링 빈이라고 함

  🔸스프링 빈의 이름은 @Bean이 붙은 메서드 명이 기본

  🔸geetBean() 메서드로 스프링 빈(객체)를 찾을 수 있음