[우아한테크코스] 5월 30일 TIL

2 minute read

[java] 요금 정책 리팩토링 중 고민

  1. if 문 없애기
    if문을 없애기 위해 어떤 방안이 있을까 고민
  • 정책들을 List로 가지며 알맞는 정책을 찾아 그 정책의 요금 계산을 하는 방안
    각 정책들은 자신이 매칭되는 조건과 자신의 정책의 계산 방안을 가지고 있다.
    Factory에서 해당 정책에 포함되는 정책들을 생성하고, List로 관리한다.
    사용시에는 팩토리에서 생성한 List를 가지고 stream으로 돌면서 매칭되는 정책을 찾아 계산을 한다.
    static으로 선언되는 상수를 줄일 수 있다는 장점이 있지만, Factory에서 정책들을 만들고, List로 만들어 생성자에 넣어주는 방안이 어색하게 느껴짐

  • enum으로 정책들의 조건과 요금 계산을 하는 방안
    enum에 각 정책에 필요한 값과 조건을 가지고 있다.
    예를 들어 AgePolicy에는 rate와 deductionFare와 자신이 매칭되는 조건을 함수로 가지고 있다.
    한 눈에 정책들을 관리할 수 있다는 장점이 있지만, static으로 선언하는 데에 있어 비용이 크다.

  1. enum으로 생성한 뒤 enum 내에 인스턴스 변수들 없애기
    거리에 대한 정책의 경우, 단위거리, 추가거리, 기본거리와 같이 멤버변수가 많아지는 것을 개선하는 방안
  • 각 정책을 전략으로 분리하는 방안
    모두 같은 계산 방식을 가지고 있고, 다른 것은 인스턴스 변수의 값이므로 추상클래스로 전략 추상화
    확장에도 유리하고, 관리도 쉽다는 장점
  1. Price 객체에서 거리, 추가요금, 나이에 따른 요금을 계산해야 하는 부분
    Price는 요금을 가진 객체일 뿐인데, 너무 많은 책임을 들고 있다고 생각했다.
    Price price = new Price(0);
    price.calculateByDistance(distance);
    price.adddExtranFare(extraFare);
    price.calculateByAge(age);
    

    위와 같은 절차지향적 구현도 맘에 들지 않았다.

  • 생성자에서 모든 연산을 수행하고, 완성된 객체를 반환하는 방안
    생성자 안에 로직이 존재할 경우 객체 생성과 동시에 로직을 수행해야 한다.
    하지만 기껏 그렇게 생성된 객체가 사용될지도 모르는데 생성하는 것에 그렇게 힘을 쓰는 것이 옳을까?

  • 값이 필요할 때 호출하는 방안
    calculate나 value같은 메서드를 값이 필요할 때 호출한다.
    하지만 이 경우, 필요한 변수들을 생성 시에 받아서 인스턴스 변수로 가지고 있어야 하므로 한 객체가 다소 많은 변수를 갖고 있어야 한다는 단점이 있다.

  1. Price 객체는 연산만 하고 그에 대한 값만 가지고 있는 객체인데 책임이 올바르지 않게 분배된 것은 아닌가?
    Price 내에서 너무 많은 다른 값(객체)으로부터의 값을 연산하고 있다.
    이렇게 될 경우 값을 관리하는 역할만을 맡고 싶은 Price가 어떤 값을 받아서 연산까지 맡게된 것이다.
  • distance와 관련된 요금 연산을 거리 계산을 담당하는 SubwayPath에 책임을 주는 방안
    객체 내 멤버변수가 많아진 이유가 책임이 아닌 객체가 연산을 하려고 해서라고 생각해 경로를 만들어주는 객체에 그 경로에 대한 요금까지 책임을 맡도록 하였다.


[Spring] serializer 객체 바인딩 오류 발생 문제 해결

    public Fare() {

    }

    public Fare(int fareByDistanceAndLine, LoginMember loginMember) {
        this.fare = FareByAge.calculate(fareByDistanceAndLine, loginMember);
    }

위와 같은 구현을 했을 시, 직렬화 에러를 만났다.
기본 생성자를 넣어주면 해결되는 것 아니었나??
아래 코드를 추가하니 해결할 수 있었다.

    public Fare(int fare) {
        this.fare = fare;
    }

직렬화 과정에서 가진 멤버변수를 가지고 역직렬화/직렬화를 진행하는데 위와 같이 진행하면 int fare만 가진 생성자가 없기 때문에 에러가 발생하는 것이었다.
기본 생성자, 멤버변수 가진 생성자가 모두 필요하다는 것을 기억하자.