TL;DR;您似乎描述了一个常见的继承问题。有一个 SongDimension 的概念,还有其他不同的概念,它们都共享一个事实,即它们是 SongDimension 的子类型。 IE。响度是一首歌曲的一个维度,节奏也是如此,流派也是如此。查找多态性和继承性。
现在来一个更长的答案。
巨大的免责声明!
请原谅任何 Java 语法错误。您似乎最精通 Java,因此即使我不是经常使用 Java 编码器,我认为最好在答案中说 Java。但一般模式适用于许多语言。
在答案的最后,我使用了一些比我应该谈论的更高级的概念,但它可能是鼓舞人心的。
在这种情况下,我希望尽可能保持一般性。我还希望能够施加任何有意义的限制,例如您对某些允许值的建议,以及允许的计算。
我会这样想这个问题:
有一个 Song 课。每首歌曲都是该类的一个实例。
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>(肯定是幼稚的实现。例如不检查 null):
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 开发人员,现在我将面临一些非常薄的冰。这很可能包含错误,所以请随意在 cmets 中 bash 所有你想要的东西。但这进一步说明了通过使用一些最小样板,一个人可以同时获得许多好处,为维度强制执行适当的值,实现自定义适当的逻辑,对每种维度类型都不同等。
在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");
}