관심사의 분리

인터페이스를 역이라 생각하고 

로미오의 역할(인터페이스)을 하는 디카프리오가 여주인공 역할인 줄리엣 역할(인터페이스)을 직접 캐스팅해야한다면 

디카프리오는 공연도 하고 동시에 여주인공도 캐스팅하는 '다양한 책임'을 가지고 있다 

 

 

 

[예시]

private DiscountPolicy discountPolicy = new FixDiscountPolicy(); 

 

OrderServiceIml 클래스에서 직접 객체(DiscountPolicy)를 생성하고 구체적으로 FixDiscountPolicy 를 선택하여 discountPolicy 에 할당한다. 

마치 디카프리오가 여주역할인 줄리엣 역할을 캐스팅하는 것 처럼

 

 

여기서 

관심사를 분리해보자.

 

배우는 본인의 역할만 수행하도록 집중해야한다  

공연을  구성하고 담당배우 캐스팅하는 것은 각 책임을 담당하는 공연 기획자를 만들어 확실히 분리를 하는 것!

인터페이스에 어떤 구현체가 할당될지는 공연 기획자가 해야한다 AppConfig가 공연기획자라고 생각하자

 

 

 

 

 

AppConfig 

 

AppConfig 등장

 

애플리케이션 전체 동작을 설정하고 구성(config)하기 위해 구현객체를 생성하고 연결하는 책임을 가지는 별도의 설정 클래스이다. (배우들을 담당 역할을 실행하는 책임만 지면된다.)

public class AppConfig {
	public MemberService memberService() {
		return new MemberServiceImpl(new MemoryMemberRepository());
	}
}​

 

 

- 실제 동작에 필요한 구현객체를 생성한다 (memoryMemberRepository 객체 생성)

- 생성한 객체 인스턴스 참조를 생성자를 통해 주입해준다 (= Dependency injection 의존성 주입) 


MemoryMemberRepository 객체를 생성한 후
public class AppConfig {
	public MemberService memberService() {
		return new MemberServiceImpl(new MemoryMemberRepository());
	}
}​


MemberServiceImpl 클래스의 생성자를 생성 한 뒤 
MemoryMemberRepository 객체의 참조값을 전달한다.

public class MemberServiceImpl implements MemberService{
    public MemberServiceImpl(MemberRepository memberRepository) {
         this.memberRepository = memberRepository;
    }
}​

 

 

의존성 주입

  • MemberServiceImpl 은 MemberRepository 인터페이스에만 의존하고
  • MemberRepository 인터페이스를 구현한 MemoryMemberRepository 구현객체에는 의존하지 않음
  • 예를들어 MemberRepository 인터페이스를 구현만 한다면 MemoryMemberRepository 에서DatabaseMemberRepository 로 바꾸어도  MemberServiceImpl 은 변경 없이 DatabaseMemberRepository 주입받아 사용가능하다. 
  • MemberServiceImpl 입장에는 의존관계를 외부(AppConfig)에서 주입해주는 것 같다해서 DI '의존성 주입'이라고 한다.
  • MemberServiceImpl 은 실행에만 집중하면 된다.

 

 

 


 

 

과정 정리 

 

 

1. 실행할때 Appconfig 를 통해 memberService 를 달라고 하면 

public class MemberApp {

	public static void main(String[] args) {
		//관심사 분리 DI
		AppConfig appConfig = new AppConfig();
		MemberService memberService = appConfig.memberService(); 
        
        ...
      }
}

 

 

2. MemberServiceImpl 객체를 반환하면서 생성자로 MemoryMemberRepository 를 참조값으로 주입하여 사용한다. 

public class AppConfig {
	public MemberService memberService() {
		return new MemberServiceImpl(new MemoryMemberRepository());
	}
}​

 

 

 


 

여기까지 AppConfig 에서는 역할에 어떤 구현을 하는지 한눈에 보여야하는데

MemoryMemberRepository() 역할이 안보여서 리팩토링을 해보자

 

AppConfig  리팩터링 

 

 

 

리팩터링이란?

 

코드내부의 기능은 바꾸지 않고 코드 중복 제거하여 가독성을 높이고 개선하는 방식으로 재조정하는 것

 

 

 

 

어떻게? 

new MemoryMemberRepository() 스크랩하고 alt + shift + m 단축키 누르고 Extract Method 창을 연다 

 

 

* Ctrl + Alt + M(Extract Method) 단축키가 보편적인데 안되길래

검색하면 바로 나오는 해결방법이 Geforce Experience 앱에 단축키를 먹어서라고.. 근데 삭제를 해도 안됨

알고보니 단축키가 다른거였다

 

 

 

memberRepository 라고 변경하면 MemoryMemberRepository 에서 memberRepository 로 모두 바뀐다

 

 

[리팩터링 전]

public class AppConfig {
	public MemberService memberService() {
		return new MemberServiceImpl(new MemoryMemberRepository());
	}

	public OrderService orderService() {
		return new OrderServiceImpl(new MemoryMemberRepository(),new FixDiscountPolicy());
	}
}

 

 

[리팩터링 후]

public class AppConfig {

	public MemberService memberService() {
		return new MemberServiceImpl(memberRepository());
	}
	
    //리팩터링
	public MemoryMemberRepository memberRepository() {
		return new MemoryMemberRepository();
	}
	
	public OrderService orderService() {
		return new OrderServiceImpl(memberRepository(),new FixDiscountPolicy()); 
	}
}

 

MemoryMemberRepository 를 반환해주는 역할을 만들어서

memberService, orderService 의 참조값에 반복되는 new MemoryMemberRepository() 객체를 대신해 사용한다.

 

예를들어 DatabaseMemberRepository 로 변경하면 일일이 바꿔줄 필요 없이 해당 코드만 바꿔주면 다 변경가능하니까 

코드가 쉬워진다.

public MemoryMemberRepository memberRepository() {
    return new DatabaseMemberRepository();
}

 

 

 

orderService() 부분도 다시 리팩터링 해보자면 

discountPolicy()을 만들어줌으로써 리턴값만 바꿔주면

FixDiscountPolicy() , RateDiscountPolicy() 을 사용하는 리턴값들을 일일이 바꿀 필요가 없다.

public OrderService orderService() {
    return new OrderServiceImpl(memberRepository(), discountPolicy()); //discountPolicy()로 대체해주기
}

public DiscountPolicy discountPolicy() {
	return new FixDiscountPolicy(); 
	//return new RateDiscountPolicy(); 
}

 

 

 

리팩터링 장점

  • 역할을 구현 명확히 분리
  • 특히 역할이 잘 드러남
  • 중복 제거

 

반응형
LIST

+ Recent posts