umbum
57
2019-07-19 19:01:34
10
999

Spring MVC에서 비슷한 로직의 두 서비스 메서드를 하나로 합치기.



안녕하세요. 

고민하다 좋은 방법이 있을까 해서 질문 드립니다.

아래와 같은 상황에서 두 서비스 메서드를 깔끔하게 하나로 합칠 방법이 있을까요?

감사합니다.

// 컨트롤러는 하나로 합칠 수 없는 상황. PostMapping을 반드시 써야하는 상황임.
public class Controller {
    @PostMapping("/getUserByCi")
    public String getUserInfoByCi(@RequestBody UserInfoRequest userInfoRequest) {
        return service.getUserInfoByCi(userInfoRequest);
    }

    @PostMapping("/getUserWithMileageByCi")
    public String getUserWithMileageByCi(@RequestBody UserInfoRequest userInfoRequest) {
        return service.getUserWithMileageByCi(userInfoRequest);
    }
}

// 비즈니스 로직이 동일하니 두 메서드를 하나로 합치고싶다... 좋은 방법은?
public class Service {
    public String getUserInfoByCi(UserInfoRequest userInfoRequest) {
        // ...동일 코드...
        memberInfoMapper.readByCi(decryptedCi);
        // ...동일 코드2...
    }

    public String getUserWithMileageByCi(UserInfoRequest userInfoRequest) {
        // ...동일 코드...
        memberInfoMapper.readWithMileageByCi(decryptedCi);
        // ...동일 코드2...
    }
}


0
  • 답변 10

  • 지나가던신입
    528
    2019-07-19 19:21:29

    이렇게는 어떠세용? decryptedCi가 어디서 튀어나온ㅇ 변수인지 모르겠어서 임시로 적어놨는데..

    public class Service {
        public String getUserInfoByCi(UserInfoRequest userInfoRequest) {
            sum(1, decryptedCi);
        }
    
        public String getUserWithMileageByCi(UserInfoRequest userInfoRequest) {
           sum(2, decryptedCi);
        }
    }
    public void sum(int target, (어떤변수인지모르겠음)decryptedCi){
        // ...동일코드
        if(target == 1){
             memberInfoMapper.readByCi(decryptedCi);
        }else{
            memberInfoMapper.readWithMileageByCi(decryptedCi);
        }
        // ...동일코드2
    }


  • umbum
    57
    2019-07-19 19:25:32

    @지나가던신입

    감사합니다. 생각해봤던 방법이긴한데요, 제3자가 보면 0,1로 이를 구분하는건 가독성이나 의미상 좋지 않고, 단순히 이 분기를 위해서 별도의 코드 타입을 만들어서 쓰는 것도 별로 좋지 않은 것 같아서 다른 방법이 없을까 생각하고 있습니다.


  • 지나가던신입
    528
    2019-07-19 19:29:40

    주석을 달아놓으면 상관없지 않을까요? 구분이면 아예 메서드명을 스트링으로 보내신다던지

    public class Service {
        public String getUserInfoByCi(UserInfoRequest userInfoRequest) {
            sum("UserInfoByCi", decryptedCi);
        }
    
        public String getUserWithMileageByCi(UserInfoRequest userInfoRequest) {
           sum("UserWithMileageByCi", decryptedCi);
        }
    }
    public void sum(String target, (어떤변수인지모르겠음)decryptedCi){
        // ...동일코드
        if(target.equals("UserInfoByCi")){
             memberInfoMapper.readByCi(decryptedCi);
        }else{
            memberInfoMapper.readWithMileageByCi(decryptedCi);
        }
        // ...동일코드2
    }


  • umbum
    57
    2019-07-19 19:38:57

    @지나가던신입


    그렇죠... 지금까지 말씀하신 부류의 방법이 사실 제일 간단하고 쉬운 방법이긴 한데요, 이게 좋은 설계일까?? 다른 더 좋은 방법은 없을까?하는 고민이 들기는 하네요 ㅎㅎ.

    답변 정말 감사합니다.

  • 지나가던신입
    528
    2019-07-19 19:44:14

    흠..ㅠㅠ 저도 항상 코딩하면서 이것도 더 줄일 수 있지 않을까? 이건 더 잘 읽히게 짤 수 있지 않을까? 하면서 요리조리해보는데 넘 어렵네용.. 별거아닌 답변에 감사하다고 해주셔서 제가 더 감사하네욥ㅋㅋㅋ

  • umbum
    57
    2019-07-19 19:46:29
    @지나가던신입

    ㅋㅋㅋ그러게요 개발자는 항상 고민하는 직업인거같아요.
    신경써서 답변해주시는데 당연히 감사하죠ㅎㅎ
    주말 잘 보내시길 바랍니다
  • 지나갈게요
    24
    2019-07-20 00:05:18

    개인적으로 선호하는 방법이라. 참고하시라고 남겨봅니다.

    전제는 플래그에 의한 분기는 확장 가능성이 존재한다고 보고 있습니다. 


    1. 컨트롤러는 유사해도 나눕니다.

    2. 서비스도 유사해도 나눕니다.

    3. 이제 중복되는 로직만 별도로 생각하고. 유틸. 헬퍼. 혹은 다른 것으로 나눕니다. 

    해당 상황에서는 인자로 술어함수를 사용할 수 있는 상황이지 않을까 생각됩니다. 혹은... 단순히  동일코드 1.2만 private메서드로 빼더라도. 메서드 내의 호출에 일관성이 생기리라 생각됩니다. 전략패턴의 구현도 있겠지만. 초반에는 지양하는 편입니다.



  • 지나갈게요
    24
    2019-07-20 00:11:36

    더하자면.. 저런동작은 보통. process를 붙인 메서드로 구분하여.. process1{a1.b1.c1..}혹은 process2{a1.b2.c1} 저는 이렇게 나눕니다.

  • umbum
    57
    2019-07-20 09:01:01

    @지나갈게요


    동일코드1과 동일코드2는 리턴을 포함한, 그리 길지 않은 try-catch문장 같은 거라서, 별도의 메서드로 빼면 어차피 그걸 상위 메서드에서 호출해서 다시 리턴해주어야 하기 때문에 메서드로 분리하기가 조금 그랬어요 ㅎㅎ. 그래서 패턴같은걸 좀 생각해보고 있었는데요, 코드를 좀 더 구체적으로 쓰면 이런 모양새입니다. 지금 코드를 볼 수 없어서 정확히 기억은 안나지만...

    method {
    try {
        a = f()
        a..
        a....
    } catch() {
        return new ResponseEntity
    }
    
    // 여기만 다르다.
    c = mapper.read()
    
    if (c == ??) 
        return new ResponseEntity
    else
        return new ResponseEntity
    }


    개인적으로 다른분께도 여쭤봤는데 애초에 컨트롤러를 합칠 수 없기 때문에 서비스도 합치기 어렵게 되어 있는 구조라고 하시더라구요. 그래서 일단은 이렇게 두고 다른 작업부터 하려고 합니다.

    답변 감사합니다 ㅎㅎ

  • 지나갈게요
    24
    2019-10-07 23:18:32

    만약. Before after로직이 고정되어있다면요. OOP로 전략 패턴을 구현하거나.. 함수형 인터페이스를 파리미터로 받는 방법이 있긴합니다.(혹은 aop)

    다만.. 실제 코딩때는. 둘다 정말 필요하지 않으면 비슷한 메서드 여럿을 만드는것을 추천드립니다.

  • 로그인을 하시면 답변을 등록할 수 있습니다.