How to expand this design for universal converter in java?

Here is a small piece of currency conversion code:

public enum CurrencyType { DOLLAR(1), POUND(1.2), RUPEE(.25); private CurrencyType(double factor) { this.factor = factor; } private double factor; public double getFactor() { return factor; } } public class Currency { public Currency(double value, CurrencyType type) { this.value = value; this.type = type; } private CurrencyType type; private double value; public CurrencyType getCurrencyType() { return type; } public double getCurrencyValue() { return value; } public void setCurrenctyValue(double value){ this.value = value; } } public class CurrencyConversion { public static Currency convert(Currency c1, Currency c2) throws Exception { if (c1 != null && c2 != null) { c2.setCurrenctyValue(c1.getCurrencyValue() * c1.getCurrencyType().getFactor() * c2.getCurrencyType().getFactor()); return c2; } else throw new Exception(); } } 

I would like to improve this code so that it works for different conversion units, for example: kilograms to kilograms, miles to kilometers, etc. Something like that:

 public class ConversionManager<T extends Convertible> { public T convert(T c1, T c2) { //return null; } } 

Appreciate your ideas and suggestions.

+4
source share
3 answers

This is an object oriented way to do this, in my opinion. Note that you can also templatize by data type, but I just used doubles here, as they can represent any scalar units. This provides a good way to handle conversions between units of different metrics, as you requested: distance, currency, mass, etc.

 public interface Metric { public String getReferenceUnit(); } public class Distance implements Metric { public String getReferenceUnit() { return new String("Meters"); } } public interface Units<T extends Metric> { public double getToReferenceFactor(); } public class Kilometers implements Units<Distance> { public double getToReferenceFactor() { return 1000; } } static <T extends Metric> double convert(Units<T> from, Units<T> to) { return from.getToReferenceFactor() * (1.0 / to.getToReferenceFactor()); } 
+4
source

Enums in java, unfortunately, do not support interfaces or superclasses (I would like to find out the correct reason for this).

What you can do is declare annotation for your enum types (e.g. @Convertible) and access its coefficient using reflection. This is pretty ugly and you can't use the "T extends Convertible" expressions in generics.

+1
source

Here is a universal converter that uses hollow matrices, and this makes a transitive closure to combine well-known converters. In this case, it converts units of length:

 import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Converter { private static final Map<String, Map<String, Double>> FACTOR_MAP = new HashMap<String, Map<String, Double>>(); public static double convert(String from, String to, double value) { List<Step> stack = new ArrayList<Step>(); stack.add(new Step(from, value)); while (!stack.isEmpty()) { Step s = stack.remove(0); double val = s.value; String source = s.unit; if (source.equals(to)) { return val; } Map<String, Double> map = FACTOR_MAP.get(source); if (map != null) { for (Map.Entry<String,Double> entry: map.entrySet()) { stack.add(new Step(entry.getKey(), val*entry.getValue())); } } } throw new IllegalArgumentException("Cannot not convert from " + from + " to " + to); } public static void registerFactor(String from, String to, double factor) { putFactor(from, to, factor); putFactor(to, from, 1.0/factor); } private static void putFactor(String from, String to, double factor) { Map<String, Double> map = FACTOR_MAP.get(from); if (map == null) { map = new HashMap<String, Double>(); FACTOR_MAP.put(from, map); } map.put(to, factor); } static { registerFactor("cm", "mm", 10); registerFactor("in", "cm", 2.54); registerFactor("in", "pt", 72); registerFactor("pc", "pt", 12); registerFactor("px", "mm", 0.28); } private static class Step { private String unit; private double value; Step(String unit, double value) { this.unit = unit; this.value = value; } } } 

The following program:

 public class Main { private static final String UNITS[] = {"cm", "mm", "in", "pt", "pc", "px"}; public static void main(String[] args) { for (String unit1: UNITS) { for (String unit2: UNITS) { System.out.println("1" + unit1 + " = " + Converter.convert(unit1, unit2, 1) + unit2); } } } } 

gives the following results:

 1cm = 1.0cm 1cm = 10.0mm 1cm = 0.39370078740157477in 1cm = 28.346456692913385pt 1cm = 2.3622047244094486pc 1cm = 35.71428571428571px 1mm = 0.1cm 1mm = 1.0mm 1mm = 0.03937007874015748in 1mm = 2.8346456692913384pt 1mm = 0.23622047244094485pc 1mm = 3.571428571428571px 1in = 2.54cm 1in = 25.4mm 1in = 1.0in 1in = 72.0pt 1in = 6.0pc 1in = 90.71428571428571px 1pt = 0.035277777777777776cm 1pt = 0.35277777777777775mm 1pt = 0.013888888888888888in 1pt = 1.0pt 1pt = 0.08333333333333333pc 1pt = 1.2599206349206347px 1pc = 0.42333333333333334cm 1pc = 4.233333333333333mm 1pc = 0.16666666666666666in 1pc = 12.0pt 1pc = 1.0pc 1pc = 15.119047619047619px 1px = 0.028000000000000004cm 1px = 0.28mm 1px = 0.011023622047244094in 1px = 0.7937007874015748pt 1px = 0.06614173228346457pc 1px = 1.0px 
+1
source

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


All Articles