Abstract class for different types of units.

i have different classes representing units of measure (volume, weight, distance), with an enumeration with a value for storing the values ​​of the base type transformation.

The problem is that there is a lot of code duplication, and I'm sure there is an elegant way to write an abstract class that would avoid it. I do not know how I should declare this class. Here is the volume class:

import java.math.BigDecimal; import lombok.Data; @Data public class Volume { public enum Unit { CUBIC_METER(new BigDecimal("1")), // CUBIC_METER // 1 m3 = 61023.7 inch3 CUBIC_INCH(new BigDecimal("61023.7")); private Unit(BigDecimal m3Value) { this.m3Value = m3Value; } public final BigDecimal m3Value; } // internally, we store the volume in m3 private final BigDecimal volumeInM3; public Volume() { volumeInM3 = BigDecimal.ZERO; } public Volume(final String volumeValue, final Unit volumeUnit) { this(new BigDecimal(volumeValue), volumeUnit); } public Volume(final BigDecimal volumeValue, final Unit volumeUnit) { if (volumeValue.signum() == 0) { volumeInM3 = BigDecimal.ZERO; } else { volumeInM3 = volumeValue.divide(volumeUnit.m3Value, NumberUtil.MC); } } /** * Return the volume in the unit given in param * @param volumeUnit * @return */ public BigDecimal getAs(final Unit volumeUnit) { return volumeInM3.multiply(volumeUnit.m3Value, NumberUtil.MC); } public Volume add(final Volume volumeToAdd) { BigDecimal newVolumeValue = volumeToAdd.volumeInM3.add(volumeInM3, NumberUtil.MC); return new Volume(newVolumeValue, Volume.Unit.CUBIC_METER); } public Volume divide(final Volume divisor) { BigDecimal newVolumeValue = volumeInM3.divide(divisor.volumeInM3, NumberUtil.MC); return new Volume(newVolumeValue, Volume.Unit.CUBIC_METER); } public boolean isZero() { if (volumeInM3.signum() == 0) return true; return false; } public boolean isEqual(final Volume another) { if (volumeInM3.compareTo(another.volumeInM3) == 0) return true; return false; } } 

And here is a pretty similar weight class:

 import java.math.BigDecimal; import lombok.Data; @Data public class Weight { // the value stored with enum is the value used to convert the unit to kilogramm, // wich is the reference unit public enum Unit { KILOGRAM(new BigDecimal("1")), // 1 kg = 1000 g GRAM(new BigDecimal("1000")), // 1 kg = 2.20462 pounds POUND(new BigDecimal("2.20462")); private Unit(BigDecimal kgValue) { this.kgValue = kgValue; } private final BigDecimal kgValue; } // internally, we store the weight inKg private final BigDecimal weightInKg; public Weight() { weightInKg = BigDecimal.ZERO; } public Weight(final String weightValue, final Unit weightUnit) { this(new BigDecimal(weightValue), weightUnit); } public Weight(final BigDecimal weightValue, final Unit weightUnit) { if (weightValue.signum() == 0) { weightInKg = BigDecimal.ZERO; } else { weightInKg = weightValue.divide(weightUnit.kgValue, NumberUtil.MC); } } /** * Return the weight in the unit given in param * @param weightUnit * @return */ public BigDecimal getAs(final Unit weightUnit) { return weightInKg.multiply(weightUnit.kgValue, NumberUtil.MC); } public Weight add(final Weight weightToAdd) { BigDecimal newWeightValue = weightToAdd.weightInKg.add(weightInKg, NumberUtil.MC); return new Weight(newWeightValue, Weight.Unit.KILOGRAM); } public Weight divide(final Weight divisor) { BigDecimal newWeightValue = weightInKg.divide(divisor.weightInKg, NumberUtil.MC); return new Weight(newWeightValue, Weight.Unit.KILOGRAM); } public boolean isZero() { if (weightInKg.signum() == 0) return true; return false; } public boolean isEqual(final Weight another) { if (weightInKg.compareTo(another.weightInKg) == 0) return true; return false; } } 

When the volume is initialized, the user is forced to explicitly provide the device.

 Volume myCubicMeter, myCubicInch; myCubicMeter = new Volume("1", Volume.Unit.CUBIC_METER); myCubicInch = new Volume("1", Volume.Unit.CUBIC_INCH); 

What I'm trying to achieve is an abstract class that implements all the methods and forces the subclasses to implement an enumeration with values. What would be the right way to do this?

+4
source share
1 answer

In Java, enumerations are classes that are subclasses of the provided Enum class.

You cannot give them a common abstract ancestor, and you cannot subclass them. If you really want the product to reference your units with compile-time constants from a set of enumerations, you cannot do this.

If you discard the use of enumerations and possibly declare them normal classes, then you can do it freely, like everything else, for example

 class VolumeUnit extends AbstractUnit { public static final VolumeUnit CUBIC_METER = new VolumeUnit(params); .. VolumeUnit(..) { .. } } 
+1
source

Source: https://habr.com/ru/post/1437300/


All Articles