added solution with tariff options as enum and map

This commit is contained in:
2026-06-16 02:10:12 +02:00
parent f134397da7
commit 4b71e88d44
12 changed files with 145 additions and 44 deletions
@@ -2,14 +2,12 @@ package com.pfefferminzia.petinsurance;
import java.time.LocalDate;
import com.pfefferminzia.petinsurance.animals.Dog;
import com.pfefferminzia.petinsurance.calculations.Calculations;
import com.pfefferminzia.petinsurance.calculations.InsuranceContract;
import com.pfefferminzia.petinsurance.tariffs.Tariff;
public class Main {
public static void main(String[] args) {
Dog dog = new Dog(LocalDate.of(2020, 4, 14), "Husky");
Calculations calc = new Calculations();
System.out.println(calc.calculateInsuranceSum(dog, Tariff.OPTIMAL, LocalDate.of(2026, 1, 2)));
System.out.println(new InsuranceContract(new Dog(LocalDate.of(2025, 1, 1), "Dackel"),
LocalDate.of(2026, 1, 1), Tariff.OPTIMAL));
}
}
@@ -4,7 +4,12 @@ import java.math.BigDecimal;
import java.time.LocalDate;
public sealed interface Animal permits Dog, Cat, SmallAnimal {
LocalDate birthday();
BigDecimal getBaseInsuranceSum();
default BigDecimal getPremiumAdjustment() {
return BigDecimal.ZERO;
}
}
@@ -2,6 +2,7 @@ package com.pfefferminzia.petinsurance.animals;
import java.math.BigDecimal;
import java.time.LocalDate;
import com.pfefferminzia.petinsurance.tariffs.BreedPremiumAdjustment;
public final record Dog(LocalDate birthday, String breed) implements Animal {
@@ -9,4 +10,9 @@ public final record Dog(LocalDate birthday, String breed) implements Animal {
public BigDecimal getBaseInsuranceSum() {
return BigDecimal.valueOf(2500.0);
}
@Override
public BigDecimal getPremiumAdjustment() {
return BreedPremiumAdjustment.forBreed(breed);
}
}
@@ -0,0 +1,5 @@
package com.pfefferminzia.petinsurance.calculations;
import java.math.BigDecimal;
public record CalculationResult(BigDecimal insuranceSum, BigDecimal yearlyPremium) {}
@@ -2,18 +2,43 @@ package com.pfefferminzia.petinsurance.calculations;
import java.math.BigDecimal;
import java.time.LocalDate;
import com.pfefferminzia.petinsurance.animals.Animal;
import java.time.temporal.ChronoUnit;
import com.pfefferminzia.petinsurance.tariffs.AgeTariff;
import com.pfefferminzia.petinsurance.tariffs.Tariff;
public class Calculations {
public BigDecimal calculateInsuranceSum(Animal animal, Tariff tariff,
LocalDate insuranceStartDate) {
public CalculationResult result(InsuranceContract contract) {
TariffValidator validator = new TariffValidator(insuranceStartDate);
validator.checkTariffAvailability(tariff);
BigDecimal insuranceBaseSum = animal.getBaseInsuranceSum();
return insuranceBaseSum.multiply(tariff.getRate());
Tariff tariff = contract.tariff();
BigDecimal insuranceSum =
getInsuranceSum(contract.animal().getBaseInsuranceSum(), tariff.getRate());
BigDecimal ageFactor =
ageFactorLookup(contract.animal().birthday(), contract.insuranceStartDate());
BigDecimal breedPremiumAdjustment = contract.animal().getPremiumAdjustment();
BigDecimal yearlyPremium = insuranceSum.multiply(ageFactor)
.multiply(BigDecimal.ONE.add(breedPremiumAdjustment));
return new CalculationResult(insuranceSum, yearlyPremium);
}
BigDecimal getInsuranceSum(BigDecimal baseInsuranceSum, BigDecimal tariffRate) {
return baseInsuranceSum.multiply(tariffRate);
}
BigDecimal ageFactorLookup(LocalDate birthday, LocalDate insuranceStartDate) {
if (insuranceStartDate.isBefore(birthday)) {
throw new IllegalArgumentException(
"Start der Versicherung kann nicht vor dem Geburtstag sein.");
}
long exactYears = ChronoUnit.YEARS.between(birthday, insuranceStartDate);
return AgeTariff.getFactorForAge(Math.toIntExact(exactYears));
}
}
@@ -0,0 +1,29 @@
package com.pfefferminzia.petinsurance.calculations;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import com.pfefferminzia.petinsurance.animals.Animal;
import com.pfefferminzia.petinsurance.exception.InvalidInsuranceContractException;
import com.pfefferminzia.petinsurance.tariffs.Tariff;
public record InsuranceContract(Animal animal, LocalDate insuranceStartDate, Tariff tariff) {
private static final LocalDate PREMIUM_AVAILABLE_FROM = LocalDate.of(2026, 7, 1);
public InsuranceContract {
List<String> violations = new ArrayList<>();
if (animal.birthday().isAfter(insuranceStartDate)) {
violations.add("Start der Versicherung kann nicht vor dem Geburtstag sein.");
}
if (insuranceStartDate.isBefore(PREMIUM_AVAILABLE_FROM) && tariff == Tariff.PREMIUM) {
violations.add("Die Premium Tarifvariante ist nicht vor dem 1. Juli 2026 verfügbar.");
}
if (!violations.isEmpty()) {
throw new InvalidInsuranceContractException(violations);
}
}
}
@@ -1,21 +0,0 @@
package com.pfefferminzia.petinsurance.calculations;
import java.time.LocalDate;
import com.pfefferminzia.petinsurance.exception.TariffNotAvailableException;
import com.pfefferminzia.petinsurance.tariffs.Tariff;
public class TariffValidator {
private LocalDate insuranceStartDate;
public TariffValidator(LocalDate insuranceStartDate) {
this.insuranceStartDate = insuranceStartDate;
}
public boolean checkTariffAvailability(Tariff tariff) {
if (insuranceStartDate.isBefore(LocalDate.of(2026, 7, 1)) && tariff == Tariff.PREMIUM) {
throw new TariffNotAvailableException(
"Die Premium Tarifvariante ist nicht vor dem 1. Juli 2026 verfügbar.");
}
return true;
}
}
@@ -0,0 +1,17 @@
package com.pfefferminzia.petinsurance.exception;
import java.util.List;
public class InvalidInsuranceContractException extends RuntimeException {
private final List<String> violations;
public InvalidInsuranceContractException(List<String> violations) {
super(String.join("\n", violations));
this.violations = List.copyOf(violations);
}
public List<String> getViolations() {
return violations;
}
}
@@ -1,8 +0,0 @@
package com.pfefferminzia.petinsurance.exception;
public class TariffNotAvailableException extends RuntimeException {
public TariffNotAvailableException(String message) {
super(message);
}
}
@@ -0,0 +1,27 @@
package com.pfefferminzia.petinsurance.tariffs;
import java.math.BigDecimal;
public enum AgeTariff {
UP_TO_TWO(2, new BigDecimal("0.2")), UP_TO_FIVE(5, new BigDecimal("0.25")), UP_TO_SEVEN(7,
new BigDecimal("0.28")), OVER_SEVEN(Integer.MAX_VALUE, new BigDecimal("0.3"));
private final int maxAge;
private final BigDecimal factor;
private AgeTariff(int maxAge, BigDecimal factor) {
this.maxAge = maxAge;
this.factor = factor;
}
public static BigDecimal getFactorForAge(int age) {
for (AgeTariff rate : values()) {
if (age <= rate.maxAge) {
return rate.factor;
}
}
throw new AssertionError("Unexpected age: " + age);
}
}
@@ -0,0 +1,18 @@
package com.pfefferminzia.petinsurance.tariffs;
import java.math.BigDecimal;
import java.util.Map;
public final class BreedPremiumAdjustment {
private static final Map<String, BigDecimal> ADJUSTMENTS = Map.of(
"Dackel", new BigDecimal("-0.1"),
"Bernhardiner", new BigDecimal("0.1")
);
public static BigDecimal forBreed(String breed) {
return ADJUSTMENTS.getOrDefault(breed, BigDecimal.ZERO);
}
private BreedPremiumAdjustment() {}
}
@@ -3,7 +3,7 @@ package com.pfefferminzia.petinsurance.tariffs;
import java.math.BigDecimal;
public enum Tariff {
KOMPAKT(BigDecimal.ONE), OPTIMAL(BigDecimal.valueOf(1.2)), PREMIUM(BigDecimal.valueOf(1.4));
KOMPAKT(BigDecimal.ONE), OPTIMAL(new BigDecimal("1.2")), PREMIUM(new BigDecimal("1.4"));
private final BigDecimal rate;