게터 만있는 인터페이스에서 코드 냄새가 나는가?


10

(내가 본 이 질문을 하지만, 첫 번째 대답이 더 많은 설계에 대한보다 자동 속성에 대한 가고, 두 번째는 말한다 소비자의 데이터 저장 코드를 숨길 수 있는지 내가 원하는 것입니다 아니에요, / 내 코드 않습니다, 그래서 다른 의견을 듣고 싶습니다)

나는이 매우 유사 엔티티가 HolidayDiscountRentalDiscount'는 적어도 지속되는 경우로 길이 할인을 대표 numberOfDays하는 percent할인 적용을'. 테이블에는 다른 상위 엔터티에 대한 fks가 있으며 다른 위치에서 사용되지만 사용되는 경우 최대 적용 가능한 할인을 얻는 일반적인 논리가 있습니다. 예를 들어,의 HolidayOffer수는 개 HolidayDiscounts이며 비용을 계산할 때 적용 가능한 할인을 계산해야합니다. 렌탈과 동일합니다 RentalDiscounts.

논리가 동일하기 때문에 단일 위치에 유지하고 싶습니다. 이것이 다음 방법, 술어 및 비교기의 기능입니다.

Optional<LengthDiscount> getMaxApplicableLengthDiscount(List<LengthDiscount> discounts, int daysToStay) {
    if (discounts.isEmpty()) {
        return Optional.empty();
    }
    return discounts.stream()
            .filter(new DiscountIsApplicablePredicate(daysToStay))
            .max(new DiscountMinDaysComparator());
}

public class DiscountIsApplicablePredicate implements Predicate<LengthDiscount> {

    private final long daysToStay;

    public DiscountIsApplicablePredicate(long daysToStay) {
        this.daysToStay = daysToStay;
    }

    @Override
    public boolean test(LengthDiscount discount) {
        return daysToStay >= discount.getNumberOfDays();
    }
}

public class DiscountMinDaysComparator implements Comparator<LengthDiscount> {

    @Override
    public int compare(LengthDiscount d1, LengthDiscount d2) {
        return d1.getNumberOfDays().compareTo(d2.getNumberOfDays());
    }
}

필요한 유일한 정보는 일 수이므로 인터페이스는 다음과 같습니다.

public interface LengthDiscount {

    Integer getNumberOfDays();
}

그리고 두 개체

@Entity
@Table(name = "holidayDiscounts")
@Setter
public class HolidayDiscount implements LengthDiscount {

    private BigInteger percent;

    private Integer numberOfDays;

    public BigInteger getPercent() {
        return percent;
    }

    @Override
    public Integer getNumberOfDays() {
        return numberOfDays;
    }

}

@Entity
@Table(name = "rentalDiscounts")
@Setter
public class RentalDiscount implements LengthDiscount {

    private BigInteger percent;

    private Integer numberOfDays;

    public BigInteger getPercent() {
        return percent;
    }

    @Override
    public Integer getNumberOfDays() {
        return numberOfDays;
    }
}

인터페이스에는 두 엔티티가 구현하는 단일 getter 메소드가 있지만 물론 작동하지만 좋은 디자인인지는 의문입니다. 값을 보유하는 것이 속성이 아닌 경우 동작을 나타내지 않습니다. 이것은 다소 간단한 경우이며, 비슷하고 복잡한 몇 가지 사례가 더 있습니다 (3-4 게터 포함).

내 질문은 이것이 나쁜 디자인입니까? 더 나은 방법은 무엇입니까?


4
인터페이스의 목적은 동작을 나타내지 않고 연결 패턴을 설정하는 것입니다. 그 의무는 구현의 방법에 달려 있습니다.
Robert Harvey

구현에 관해서는, 엄청나게 많은 상용구가 있습니다 (구조를 제공하는 것 외에는 실제로 아무것도하지 않는 코드). 당신은 그것을 모두 필요로합니까?
Robert Harvey

인터페이스의 메소드조차도 '게터 (getter)'일 뿐이며 구현에 '세터 (setter)'를 구현할 수 없다는 의미는 아닙니다 (모두 세터가있는 경우 여전히 초록을 사용할 수 있음)
рüффп

답변:


5

나는 당신의 디자인이 약간 잘못되었다고 말할 것입니다.

잠재적 인 해결책 중 하나는이라는 인터페이스를 만드는 것 IDiscountCalculator입니다.

decimal CalculateDiscount();

이제 할인을 제공해야하는 모든 클래스가이 인터페이스를 구현합니다. 할인이 며칠을 사용하는 경우 인터페이스는 구현 세부 정보이므로 실제로 신경 쓰지 않습니다.

모든 할인 클래스에이 데이터 멤버가 필요한 경우 일 수는 일종의 추상 기본 클래스에 속할 수 있습니다. 특정 클래스라면 필요에 따라 공개 또는 비공개로 액세스 할 수있는 속성을 선언하십시오.


1
나는 확실히 나는 완전히 데에 동의하고 있지 않다 HolidayDiscountRentalDiscount구현 IDiscountCalculator그들이 할인 계산기 아니에요 때문에. 다른 방법으로 계산 getMaxApplicableLengthDiscount합니다. HolidayDiscount그리고 RentalDiscount할인입니다. 할인은 계산되지 않거나 적용 가능한 할인 유형으로 계산되거나 여러 할인 중에서 선택됩니다.
user3748908

1
인터페이스는 IDiscountable이라고합니다. 구현해야 할 클래스는 무엇이든 가능합니다. 휴일 / 임대 할인 클래스가 DTO / POCO 일 경우 계산하지 않고 결과를 저장하는 것이 좋습니다.
Jon Raynor

3

질문에 대답하려면 인터페이스에 게터 만있는 경우 코드 냄새가 나지 않습니다.

코드 냄새에 대한 퍼지 메트릭의 예는 많은 메소드를 가진 bloated 인터페이스입니다 (게터가 아니더라도 그렇지 않습니다). 인터페이스 세그먼테이션 원칙을 위반하는 경향이 있습니다.

의미 수준에서 단일 책임 원칙도 위반해서는 안됩니다. 하나의 주제가 아닌 인터페이스 계약에서 여러 가지 다른 문제가 처리되는 경우 위반하는 경향이 있습니다. 이것은 때때로 식별하기 어렵고이를 식별하기위한 경험이 필요합니다.

다른 쪽에서는 인터페이스가 설정자를 정의하는지 알고 있어야합니다. 세터가 상태를 바꿀 가능성이 있기 때문입니다. 여기서 질문 할 사항 : 인터페이스 뒤의 객체가 유효한 상태에서 다른 유효한 상태로 전환합니까? 그러나 이는 주로 인터페이스의 문제가 아니라 구현 객체의 인터페이스 계약 구현입니다.

내가 당신의 접근 방식에 대한 유일한 관심사는 당신이 OR 매핑을 운영한다는 것입니다. 이 작은 경우에는 이것이 문제가되지 않습니다. 기술적으로는 괜찮습니다. 그러나 OR 매핑 개체에서는 작동하지 않습니다. 그들은 당신이 그들에 대해 수행 된 작업에서 반드시 고려해야 할 너무 많은 다른 상태를 가질 수 있습니다 ...

OR- 맵핑 된 오브젝트는 (JPA를 전제로 함) 일시적, 지속적 분리 변경되지 않음, 지속적 첨부 변경되지 않음, 지속적 분리 변경, 지속적 첨부 변경 일 수 있습니다. 해당 오브젝트에 Bean 유효성 검증을 사용하면 오브젝트가 점검되었는지 여부를 더 이상 볼 수 없습니다. 결국 OR 맵핑 된 오브젝트가 가질 수있는 10 가지 이상의 다른 상태를 식별 할 수 있습니다. 모든 작업이 이러한 상태를 올바르게 처리합니까?

인터페이스가 계약을 정의하고 구현이 따르는 경우에는 아무런 문제가 없습니다. 그러나 OR 매핑 객체의 경우 그러한 계약을 완전히 채울 수 있다는 의심이 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.