Могу ли я получить переменное число обобщенных c типов для Java классов или вообще? - PullRequest
0 голосов
/ 01 мая 2020

Я хотел бы создать общий класс данных c с именем «EnumTuple», который хранит натуральное количество различных элементов Enum из различных классов Enum вместе в одном кортеже. Допустим, у меня есть три класса Enum:

public Enum Gender {
    FEMALE, MALE, OTHER
}

public enum Age {
    YOUNG, MIDDLEAGED, OLD
}

public enum Personality {
    EXTROVERT, INTROVERT
}

Я бы хотел создать экземпляр класса EnumTuple следующим образом:

EnumTuple person1 = new EnumTuple<Gender, Age, Personality>(Gender.OTHER, Age.MIDDLEAGED, Personality.EXTROVERT);
EnumTuple person2 = new EnumTuple<Personality, Gender>(Personality.INTROVERT, Gender.FEMALE);
EnumTuple person3 = new EnumTuple<Age>(Age.OLD);

Но я понятия не имею, как туда добраться или если вообще возможно написать такой класс данных в Java или Kotlin для начала, потому что похоже, что каждый класс может иметь только фиксированное число обобщенных c типов.

Для любопытных Я пытаюсь реализовать чистую и общую версию алгоритма исключения кандидатов (https://artint.info/html/ArtInt_193.html), в которой набор входных функций - это тот набор элементов перечисления, который я пытаюсь разработать.

И, наконец, если у вас есть обходной путь для меня под рукой или вы знаете другой язык программирования, который поддерживает переменное число обобщенных c типов, пожалуйста, дайте мне знать

Ответы [ 2 ]

2 голосов
/ 01 мая 2020

Вы не можете сделать это ни в Java, ни в Kotlin, поскольку, как вы и предполагали, у каждого класса может быть только фиксированное количество обобщенных c типов.

Единственный способ обойти это здесь, без указания всех комбинаций вручную, необходимо проверять экземпляр перечислений при каждом их использовании, создавая EnumTuple с vararg Enum<*>.

например, (в Kotlin)

class EnumTuple(vararg enums: Enum<*>)

[...] или знаете другой язык программирования, который поддерживает переменное число обобщенных c типов, пожалуйста, дайте мне знать.

Эта функция поддерживается в C ++ с использованием шаблонов variadi c. https://en.cppreference.com/w/cpp/language/parameter_pack

0 голосов
/ 01 мая 2020

Исходя из вариантов использования, EnumTuple будет сравниваться с использованием каждой имеющейся функции. И количество функций является гибким, я бы предложил следующий дизайн.

  1. Добавить перечисление FeatureType, которое будет содержать все возможные функции.
  2. Добавить интерфейс Feature и каждое перечисление функции будет реализовывать этот интерфейс.
  3. В EnumTuple мы будем использовать Map<FeatureType, Feature> для хранения функций.

public enum FeatureType {
    AGE, GENDER, PERSONALITY;
}

public enum Age implements Feature {
    YOUNG, MIDDLEAGED, OLD;

    @Override
    public FeatureType getFeatureType() {
        return FeatureType.AGE;
    }
}

public enum Personality implements Feature {
    EXTROVERT, INTROVERT;

    @Override
    public FeatureType getFeatureType() {
        return FeatureType.PERSONALITY;
    }
}

public enum Gender implements Feature {
    FEMALE, MALE, OTHER;

    @Override
    public FeatureType getFeatureType() {
        return FeatureType.GENDER;
    }
}

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Assert;

public class EnumTuple {
    private Map<FeatureType, Feature> featureTypeToFeatureMap = new HashMap<>();

    public EnumTuple(List<Feature> features) {
        for (Feature feature : features) {
            featureTypeToFeatureMap.put(feature.getFeatureType(), feature);
        }
    }

    public boolean hasFeature(FeatureType featureType) {
        return featureTypeToFeatureMap.containsKey(featureType);
    }

    public Feature getFeature(FeatureType featureType) {
        return featureTypeToFeatureMap.get(featureType);
    }

    public Map<FeatureType, Boolean> getDifferenceTo(EnumTuple enumTuple) {
        if (!this.featureTypeToFeatureMap.keySet().equals(enumTuple.featureTypeToFeatureMap.keySet())) {
            throw new IllegalArgumentException("Contains different featureTypes");
        }
        Map<FeatureType, Boolean> difference = new HashMap<>();
        for (FeatureType featureType : this.featureTypeToFeatureMap.keySet()) {
            difference.put(featureType, this.getFeature(featureType).equals(enumTuple.getFeature(featureType)));
        }
        return difference;
    }

    public boolean isEqualsTo(EnumTuple other) {
        if (featureTypeToFeatureMap == null) {
            if (other.featureTypeToFeatureMap != null)
                return false;
        } else if (!featureTypeToFeatureMap.equals(other.featureTypeToFeatureMap))
            return false;
        return true;
    }

    public static void main(String[] args) {
        EnumTuple person1 = new EnumTuple(Arrays.asList(Gender.OTHER, Age.MIDDLEAGED, Personality.EXTROVERT));
        EnumTuple person2 = new EnumTuple(Arrays.asList(Gender.OTHER, Age.MIDDLEAGED, Personality.EXTROVERT));
        EnumTuple person3 = new EnumTuple(Arrays.asList(Gender.FEMALE, Age.MIDDLEAGED, Personality.EXTROVERT));
        Assert.assertTrue(person1.isEqualsTo(person2));
        Assert.assertFalse(person1.isEqualsTo(person3));
        Assert.assertEquals(person1.getDifferenceTo(person2).toString(), "{PERSONALITY=true, GENDER=true, AGE=true}");
        Assert.assertEquals(person1.getDifferenceTo(person3).toString(), "{PERSONALITY=true, GENDER=false, AGE=true}");
    }
}
...