好吧,所以我正面临着我正在写的软件的设计问题。基本上,我需要装饰器和状态模式的组合......除了用户可以定义特定的装饰器及其状态。令我惊讶的是,我找不到满足我需要的任何东西。
简要说明:它是一种语言学应用程序,应该用于任何类型的语言。语言很复杂,所以我需要一个系统,为用户提供足够的灵活性来添加他需要的组件。我的问题出现在那些组件上,我称之为“修改器”。
口语中的单词基本上是一系列音素(元音或辅音)。
音素具有特征(固有属性;基于共享特征过滤音素的能力是必不可少的),但它们也有修饰符。
修饰符基本上是可以打开或关闭的特定功能的切换或拨号(例如,元音可以是长或短),或者可以具有不同的状态(例如中文中的元音音调;中文有5个不同的音调,元音在任何给定的时间都有1个。修饰符的存在对于音素是必不可少的,但是它的确切状态并不会将它变成完全不同的音素。用户必须定义自己的STATES。我可以提供一个包含一系列常见状态的枚举(DISABLED,ENABLED,LONG,SHORT,HEAVY,LIGHT,FALLING_TONE,...),但这会使应用程序容易受到应用于不应具有某种状态的修饰符的不适当状态的影响(例如,辅音不能有下降的声调。)
对于给定的语言,用户必须提前定义其音素(以及其功能和修饰符)。问题是修饰国。因为它们没有预先定义,所以我不能使用Decorator + State模式。没有枚举或具体类,只有用户创建的对象。
我的解决方案是创建一个包含Map的WordPhoneme类。然后一个Word有一个List。显然,我将提供必要的方法来检查某个修饰符是否允许某个ModifierState等。这样,对于特定单词中的特定音素,可以获得特定的状态,并且我避免制作相同少数的5000个副本音素只是为了能够改变他们的修饰状态。
但这是最佳解决方案吗?
我的代码(并非所有内容都已实现,需要首先获得设计):
public class Word {
private List<WordPhoneme> phonemeSequence;
public Word(List<Phoneme> phonemeSequence) {
// turn List<Phoneme> into a List<WordPhoneme>, by giving each Modifier its default state.
}
}
public class WordPhoneme {
private Word word;
private Phoneme phoneme;
private Map<Modifier, ModifierState> modifierStates;
public WordPhoneme (Word word, Phoneme phoneme) {
this.word = word;
this.phoneme = phoneme;
// Map<Modifier, ModifierState> get created, each Modifier gets its default state
}
public Word getWord() { /* */ };
public Phoneme getPhoneme() { /* */ };
public List<Modifier> getModifiers;
public ModifierState getModifierState(Modifier modifier) { /* */ }
public void changeModifierState(Modifier modifier, ModifierState state) { /* throws error if not a legal state */ }
}
public abstract class Phoneme {
private final String notation;
private final List<Feature> secondaryFeatures; // voice, aspiration, palatalization, semivowel, roundedness, nasalization, vowel tones,…
private Phoneme() { /* not allowed */ }
public Phoneme(String notation){
this.notation = notation;
this.secondaryFeatures = null;
}
public Phoneme(String notation, List<Feature> secondaryFeatures){
this(notation);
this.secondaryFeatures = secondaryFeatures
}
public List<Feature> getSecondaryFeatures() { /* */ }
public List<Modifier> getModifiers() { /* */}
public boolean hasFeature(Feature feature) { /* */ }
public boolean hasModifier(Modifier modifier) { /* */ }
public ModifierState getModifierState(Modifier modifier) { /* */ }
public List<ModifierState> getPossibleModifierStates(Modifier modifier) { /* */}
public void changeModifierState(Modifier modifier, ModifierState state) { /* */ }
}
public class Consonant extends Phoneme {
private final Feature placeOfArticulation;
private final Feature mannerOfArticulation;
private Consonant() { /* not allowed */ }
public Consonant(String notation, Feature poa, Feature moa) {
super(notation);
placeOfArticulation = poa;
mannerOfArticulation = moa;
}
public Consonant(String notation, Feature poa, Feature moa, List<Feature> secondaryFeatures) {
super(notation, secondaryFeatures);
placeOfArticulation = poa;
mannerOfArticulation = moa;
}
public Feature getPlaceOfArticulation() { /* */ }
public Feature getMannerOfArticulation() { /* */ }
}
public class Vowel extends Phoneme {
private final Feature height;
private final Feature backness;
private Vowel() { /* not allowed */ }
public Vowel(String notation, Feature height, Feature backness) {
super(notation);
this.height = height;
this.backness = backness;
}
public Consonant(String notation, Feature height, Feature backness, List<Feature> secondaryFeatures) {
super(notation, secondaryFeatures);
this.height = height;
this.backness = backness;
}
public Feature getHeight() { /* */}
public Feature getBackness() { /* */ }
}
// A feature is inherent to the phoneme; changing a feature changes the phoneme.
public class Feature {
private final String name;
}
// A modifier slightly alters the phoneme whilst still retaining the phoneme’s defining features.
// A modifier can have a user-defined list of possible states. This allows for more flexibility than
// having a simple enabled/disabled toggle, e.g. the use of multiple tones, multiple degrees of vowel
// length e.g.
public class Modifier {
private final String name;
private final ModifierState defaultState;
private final List<ModifierState> possibleStates;
private Modifier() { /* not allowed */ }
public Modifier(String name, ModifierState defaultState, List<ModifierState> possibleStates) {
// check if the defaultState is a member of possibleStates
}
public List<ModifierStates> getPossibleModifierStates() { /* */ }
}
public class ModifierState {
private final String name;
}
您可能会问:但为什么要使用修饰符?是不是更容易使每个修改器成为特定的功能,然后增加音素的数量,以区分不同的功能?
不,因为: 1)它们不是单独的音素,我必须实现额外的课程或某些东西以保持相关的音素在一起,并且 2)高级功能包括共轭/变换和语言演变...当单词变得变化时,音素的修饰符通常会变为不同的状态......如果用户必须从中单独制作音素,那么这将是一个实现的噩梦。