From ea940f2c5b6450231ff9ce61f4b6704babdb0d9e Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Mon, 18 Mar 2019 16:43:36 -0400 Subject: Created an OperatableUnit interface for units that can operate. --- src/org/unitConverter/unit/BaseUnit.java | 48 ++++++- src/org/unitConverter/unit/LinearUnit.java | 57 ++++++++- src/org/unitConverter/unit/OperatableUnit.java | 169 +++++++++++++++++++++++++ 3 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 src/org/unitConverter/unit/OperatableUnit.java (limited to 'src/org') diff --git a/src/org/unitConverter/unit/BaseUnit.java b/src/org/unitConverter/unit/BaseUnit.java index 1f0c825..894d338 100755 --- a/src/org/unitConverter/unit/BaseUnit.java +++ b/src/org/unitConverter/unit/BaseUnit.java @@ -28,7 +28,7 @@ import org.unitConverter.dimension.UnitDimension; * @since 2018-12-23 * @since v0.1.0 */ -public final class BaseUnit extends AbstractUnit { +public final class BaseUnit extends AbstractUnit implements OperatableUnit { /** * Is this unit a full base (i.e. m, s, ... but not N, J, ...) * @@ -126,6 +126,35 @@ public final class BaseUnit extends AbstractUnit { return result; } + @Override + public LinearUnit negated() { + return this.times(-1); + } + + @Override + public OperatableUnit plus(final OperatableUnit addend) { + Objects.requireNonNull(addend, "addend must not be null."); + + // reject addends that cannot be added to this unit + if (!this.getSystem().equals(addend.getSystem())) + throw new IllegalArgumentException( + String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend)); + if (!this.getDimension().equals(addend.getDimension())) + throw new IllegalArgumentException( + String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend)); + + // add them together + if (addend instanceof BaseUnit) + return this.times(2); + else + return addend.plus(this); + } + + @Override + public BaseUnit reciprocal() { + return this.toExponent(-1); + } + /** * Multiplies this unit by another unit. * @@ -159,6 +188,22 @@ public final class BaseUnit extends AbstractUnit { return new LinearUnit(this, multiplier); } + @Override + public OperatableUnit times(final OperatableUnit multiplier) { + Objects.requireNonNull(multiplier, "multiplier must not be null."); + + // reject multipliers that cannot be muliplied by this unit + if (!this.getSystem().equals(multiplier.getSystem())) + throw new IllegalArgumentException(String + .format("Incompatible units for multiplication or division \"%s\" and \"%s\".", this, multiplier)); + + // multiply the units + if (multiplier instanceof BaseUnit) + return new BaseUnit(this.getDimension().times(multiplier.getDimension()), this.getSystem()); + else + return multiplier.times(this); + } + /** * Returns this unit, but to an exponent. * @@ -168,6 +213,7 @@ public final class BaseUnit extends AbstractUnit { * @since 2019-01-15 * @since v0.1.0 */ + @Override public BaseUnit toExponent(final int exponent) { return this.getSystem().getBaseUnit(this.getDimension().toExponent(exponent)); } diff --git a/src/org/unitConverter/unit/LinearUnit.java b/src/org/unitConverter/unit/LinearUnit.java index ab46f1e..64eff1f 100644 --- a/src/org/unitConverter/unit/LinearUnit.java +++ b/src/org/unitConverter/unit/LinearUnit.java @@ -27,7 +27,7 @@ import org.unitConverter.dimension.UnitDimension; * @since 2018-12-22 * @since v0.1.0 */ -public final class LinearUnit extends AbstractUnit { +public final class LinearUnit extends AbstractUnit implements OperatableUnit { /** * The value of one of this unit in this unit's base unit * @@ -134,6 +134,40 @@ public final class LinearUnit extends AbstractUnit { return result; } + @Override + public LinearUnit negated() { + return new LinearUnit(this.getBase(), -this.getConversionFactor()); + } + + @Override + public OperatableUnit plus(final OperatableUnit addend) { + Objects.requireNonNull(addend, "addend must not be null."); + + // reject addends that cannot be added to this unit + if (!this.getSystem().equals(addend.getSystem())) + throw new IllegalArgumentException( + String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend)); + if (!this.getDimension().equals(addend.getDimension())) + throw new IllegalArgumentException( + String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend)); + + // add the units + if (addend instanceof BaseUnit) + // since addend's dimension is equal to this unit's dimension, and there is only one base unit per + // system-dimension, addend must be this unit's base. + return new LinearUnit(this.getBase(), this.getConversionFactor() + 1); + else if (addend instanceof LinearUnit) + return new LinearUnit(this.getBase(), + this.getConversionFactor() + ((LinearUnit) addend).getConversionFactor()); + else + return addend.times(this); + } + + @Override + public LinearUnit reciprocal() { + return this.toExponent(-1); + } + /** * Multiplies this unit by a scalar. * @@ -164,6 +198,26 @@ public final class LinearUnit extends AbstractUnit { return new LinearUnit(base, this.getConversionFactor() * other.getConversionFactor()); } + @Override + public OperatableUnit times(final OperatableUnit multiplier) { + Objects.requireNonNull(multiplier, "multiplier must not be null."); + + // reject multipliers that cannot be muliplied by this unit + if (!this.getSystem().equals(multiplier.getSystem())) + throw new IllegalArgumentException(String + .format("Incompatible units for multiplication or division \"%s\" and \"%s\".", this, multiplier)); + + // multiply the units + if (multiplier instanceof BaseUnit) { + final BaseUnit newBase = this.getBase().times((BaseUnit) multiplier); + return new LinearUnit(newBase, this.getConversionFactor()); + } else if (multiplier instanceof LinearUnit) { + final BaseUnit base = this.getBase().times(multiplier.getBase()); + return new LinearUnit(base, this.getConversionFactor() * ((LinearUnit) multiplier).getConversionFactor()); + } else + return multiplier.times(this); + } + /** * Returns this unit but to an exponent. * @@ -173,6 +227,7 @@ public final class LinearUnit extends AbstractUnit { * @since 2019-01-15 * @since v0.1.0 */ + @Override public LinearUnit toExponent(final int exponent) { return new LinearUnit(this.getBase().toExponent(exponent), Math.pow(this.conversionFactor, exponent)); } diff --git a/src/org/unitConverter/unit/OperatableUnit.java b/src/org/unitConverter/unit/OperatableUnit.java new file mode 100644 index 0000000..ae11c41 --- /dev/null +++ b/src/org/unitConverter/unit/OperatableUnit.java @@ -0,0 +1,169 @@ +/** + * Copyright (C) 2019 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.unitConverter.unit; + +/** + * A unit that can be added, subtracted, multiplied or divided by another operatable unit, and raised to an integer + * exponent. + *

+ * In order to use two units in an operation, they must be part of the same unit system. In addition, in order for two + * units to add or subtract, they must measure the same dimension. + *

+ *

+ * It is okay for an operation to throw a {@code ClassCastException} if the operator's class cannot operate with another + * class. However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and + * {@code LinearUnit}. + *

+ * + * @author Adrien Hopkins + * @since 2019-03-17 + */ +public interface OperatableUnit extends Unit { + /** + * Returns the quotient of this unit and another. + *

+ * Two units can be divided if they are part of the same unit system. If {@code divisor} does not meet this + * condition, an {@code IllegalArgumentException} should be thrown. + *

+ *

+ * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code divisor}'s class. + * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and + * {@code LinearUnit}. + *

+ * + * @param divisor + * unit to divide by + * @return quotient + * @throws IllegalArgumentException + * if {@code divisor} is not compatible for division as described above + * @throws NullPointerException + * if {@code divisor} is null + * @throws ClassCastException + * if {@code divisor}'s class is incompatible with this unit's class + * @since 2019-03-17 + */ + default OperatableUnit dividedBy(final OperatableUnit divisor) { + return this.times(divisor.reciprocal()); + } + + /** + * Returns the difference of this unit and another. + *

+ * Two units can be subtracted if they meet the following conditions: + *

+ * If {@code subtrahend} does not meet these conditions, an {@code IllegalArgumentException} should be thrown. + *

+ *

+ * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code subtrahend}'s class. + * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and + * {@code LinearUnit}. + *

+ * + * @param subtrahend + * unit to subtract + * @return difference + * @throws IllegalArgumentException + * if {@code subtrahend} is not compatible for subtraction as described above + * @throws NullPointerException + * if {@code subtrahend} is null + * @throws ClassCastException + * if {@code subtrahend}'s class is incompatible with this unit's class + * @since 2019-03-17 + */ + default OperatableUnit minus(final OperatableUnit subtrahend) { + return this.plus(subtrahend.negated()); + } + + /** + * @return this unit negated, i.e. -this + * @since 2019-03-17 + */ + OperatableUnit negated(); + + /** + * Returns the sum of this unit and another. + *

+ * Two units can be added if they meet the following conditions: + *

+ * If {@code addend} does not meet these conditions, an {@code IllegalArgumentException} should be thrown. + *

+ *

+ * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code addend}'s class. + * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and + * {@code LinearUnit}. + *

+ * + * @param addend + * unit to add + * @return sum + * @throws IllegalArgumentException + * if {@code addend} is not compatible for addition as described above + * @throws NullPointerException + * if {@code addend} is null + * @throws ClassCastException + * if {@code addend}'s class is incompatible with this unit's class + * @since 2019-03-17 + */ + OperatableUnit plus(OperatableUnit addend); + + /** + * @return reciprocal of this unit + * @since 2019-03-17 + */ + OperatableUnit reciprocal(); + + /** + * Returns the product of this unit and another. + *

+ * Two units can be multiplied if they are part of the same unit system. If {@code multiplier} does not meet this + * condition, an {@code IllegalArgumentException} should be thrown. + *

+ *

+ * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code multiplier}'s class. + * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and + * {@code LinearUnit}. + *

+ * + * @param multiplier + * unit to multiply by + * @return product + * @throws IllegalArgumentException + * if {@code multiplier} is not compatible for multiplication as described above + * @throws NullPointerException + * if {@code multiplier} is null + * @throws ClassCastException + * if {@code multiplier}'s class is incompatible with this unit's class + * @since 2019-03-17 + */ + OperatableUnit times(OperatableUnit multiplier); + + /** + * Returns the result of raising this unit to the exponent {@code exponent}. + * + * @param exponent + * exponent to exponentiate by + * @return result of exponentiation + * @since 2019-03-17 + */ + OperatableUnit toExponent(int exponent); +} -- cgit v1.2.3