TL; DR;Вы, кажется, описываете общую проблему наследования.Существует концепция SongDimension, и есть другие концепции, которые разделяют тот факт, что они являются подтипами SongDimension.Т.е. громкость - это измерение песни, как темп, жанр и т. Д. Поиск полиморфизма и наследования.
Теперь перейдем к более длинному ответу.
Огромный отказ от ответственности!
Пожалуйста, прости любые ошибки синтаксиса Java.Вы, кажется, наиболее свободно владеете Java, поэтому, хотя я не частый Java-программист, я подумал, что лучше будет говорить на Java в ответе.Но общая схема применима ко многим языкам.
В конце ответа я использую некоторые концепции, которые намного более продвинуты, чем мне следовало бы говорить, но это может быть вдохновляющим или что-то в этом роде.
В подобных случаях я хотел бы сохранить как можно больше общности.Я также хочу иметь возможность налагать любые ограничения, которые имеют смысл, например, то, что вы предлагаете с определенными допустимыми значениями, но также и в отношении того, какие вычисления разрешены.
Я бы подумал об этой проблеме следующим образом:
Есть класс Song.Каждая песня является экземпляром этого класса.
Класс песни содержит коллекцию объектов типа SongDimension:
public class Song {
public string title;
public string artist;
public List<SongDimension> songDimensions;
}
Класс SongDimension является абстрактным классом со следующей сигнатурой
public abstract class SongDimension {
public abstract string GetValue();
}
Затем для каждого типа измерения вы можете сгенерировать перечисления для приемлемых значений или применить собственную логику, как в случае с громкостью, например:
public enum Genres {
ClassicRock, Classical, Reggae
}
public class Genre extends SongDimension {
private Genres _genre;
public string GetValue(){
switch(_genre) {
case ClassicRock: return "Classic Rock";
default: return _genre.name();
}
}
public Genre(Genres whichGenre) {
_genre = whichGenre;
}
}
public class Loudness extends SongDimension {
private int _loudness;
public string GetValue(){
return String.valueOf(_loudness);
}
public int GetIntValue() {
return _loudness;
}
public Loudness(int howLoud) {
if(howLoud < 9 || howLoud > 11) throw new IllegalArgumentException();
_loudness = howLoud;
}
// Add more relevant operations on the value here,
// maybe you can take differences of loudnesses for instance?
}
Для использованиявсего этого вы можете создать пару таких песен:
Song EineKleineNachtMusik = new Song();
EineKleineNachtMusik.songDimensions.Add(new Genre(Genres.Classical));
EineKleineNachtMusik.songDimensions.Add(new Loudness(9));
Song BackInBlack = new Song();
BackInBlack.songDimensions.Add(new Genre(Genres.ClassicRock));
BackInBlack.songDimensions.Add(new Loudness(11));
for(SongDimensions d : EineKleineNachtMusik.songDimensions){
System.out.println(d.GetValue());
}
/// prints:
/// Classical
/// 9
Самая большая ценность всего этого заключается в том, что он позволяет вам получать различную информацию о песне не как строки, а как надлежащие объекты.Риск использования строковых заполнителей для значений и типов заключается в том, что вы можете получить разные интерпретации того, что на самом деле означает «11».Даже если вы можете назначить значения «9», «10» или «11» только как «громкость», ничто не мешает вам позднее трактовать «10» как нечто совершенно иное по ошибке, например, длину песнив минутах.
Таким образом, мы можем создавать объекты, которые семантически здоровы, и включать пользовательскую логику в различные виды признаков.Например, мы могли бы реализовать класс Loudness Comparable<Loudness>
(наивная реализация наверняка. Например, не проверять ноль):
public class Loudness extends SongDimension implements Comparable<Loudness> {
...
// Same as before with the addition of the following:
@Override public int compareTo(Loudness that) {
if(_loudness < that.GetIntValue()) return -1;
if(_loudness == that.GetIntValue()) return 0;
if(_loudness > that.GetIntValue()) return 1;
}
}
Теперь я пойду на очень тонкий лед, учитывая, чтоЯ не разработчик Java.Это будет НАИБОЛЕЕ ВЕРОЯТНО содержать ошибки, поэтому, пожалуйста, не стесняйтесь бить все, что вы хотите в комментариях.Но это дополнительно иллюстрирует тот факт, что при использовании некоторого минимального стандартного шаблона можно получить сразу много преимуществ, принудительно применяя правильные значения для измерений, применяя пользовательскую соответствующую логику, различную для каждого типа измерения и т. Д.
С добавлением небольшого вспомогательного метода в классе Song
для извлечения определенного типа измерения:
public class Song {
...
// same as above, with the addition of:
public <T extends SongDimension> T GetDimension(Class<T> dimType) {
return songDimensions.stream().filter(dim -> dim instanceof
dimType).Collect(Collectors.toList()).iterator().next()
}
}
Затем мы можем сравнить две песни следующим образом:
Loudness l1 = EineKleineNachtMusik.GetDimension(Loudness.class);
Loudness l2 = BackInBlack.GetDimension(Loudness.class);
if(l1 != null && l2 != null && l1.compareTo(l2) < 0) {
System.out.println("Yup, BackInBlack is the louder of the two");
}