前面只是简单介绍了sphinx4如何通过配置文件中的实例名称,利用反射来创建对象。对象的创建本身比较简单,但是对象属性之间的依赖关系就变得很复杂了。一个对象往往会引用到很多其他属性,而属性的类型可以是基本类型,也可以是类类型。
在sphinx4中,一个对象依赖的属性是通过<property>和<propertyList>这两个标签来实现的。我们主要介绍一下<property>,<propertyList>用法类似,不再介绍。下面我们还是以HelloWord这个例子为切入点进行分析:
首先我们看一下 helloworld.config.xml配置文件中recognizer的相关配置信息:
<component name="recognizer" type="edu.cmu.sphinx.recognizer.Recognizer">
<property name="decoder" value="decoder"/>
<propertylist name="monitors">
<item>accuracyTracker </item>
<item>speedTracker </item>
<item>memoryTracker </item>
</propertylist>
</component>
这个组件的名称是“recognizer”,对应具体的java类的名称是“edu.cmu.sphinx.recognizer.Recognizer”,解析的时候保存在RawPropertyData的className成员变量中,sphinx4就是利用它,然后通过反射的方式来创建Recognizer对象的。
下面重点分析一下recognizer的属性<property>。
在recognizer中,有一个属性它的name为decoder,value为decoder:
<property name="decoder" value="decoder"/>
虽然这两个值都是decoder,但是他们有着本质的区别。name="decoder" 和Recognizer这个类中的成员变量是对应的,我们看下Recognizer中的定义:
public class Recognizer implements Configurable, ResultProducer {
/** The property for the decoder to be used by this recognizer. */
// Decoder成员变量,作为recognizer的一个属性
@S4Component(type = Decoder.class)
public final static String PROP_DECODER = "decoder";
/** The property for the set of monitors for this recognizer */
@S4ComponentList(type = Monitor.class)
public final static String PROP_MONITORS = "monitors";
//省略其他代码。。。
}
name="decoder"对应 public final static String PROP_DECODER = "decoder",这个两个必须相同,否则无法通过注解的方式对它进行赋值。
而value="decoder"表示的是在这个xml配置文件中,查找叫着decode的组件,如下:
<component name="decoder" type="edu.cmu.sphinx.decoder.Decoder">
<property name="searchManager" value="searchManager"/>
</component>
我们看到在Recognizer中,成员变量PROP_DECODER有一个注解:
@S4Component(type = Decoder.class)
publicfinalstatic String PROP_DECODER = "decoder";
这个注解S4Component的type设置为 Decoder.class,这样Recognizer引用到的成员变量decoder,实际上对应的是edu.cmu.sphinx.decoder.Decoder这个类,但是这个在配置文件中只是一个字符串,还必须通过反射来实际创建这个对象。
那么在Recognizer中是如何得到这个Decoder对象呢?
我们知道,受配置文件管理的对象都实现了Configurable接口,Recognizer 也不例外,同时必须实现其中的抽象方法newProperties:
public void newProperties(PropertySheet ps) throws PropertyException {
// 解码器
decoder = (Decoder) ps.getComponent(PROP_DECODER);
// 属性监听器
monitors = ps.getComponentList(PROP_MONITORS, Monitor.class);
// 类的实例名称
name = ps.getInstanceName();
}
这个方法在属性发生变化的时候会自动回调,同时把新的属性对象通过PropertySheet传递进来,在这个方法中有这么一句:
decoder = (Decoder) ps.getComponent(PROP_DECODER);
即通过属性名称PROP_DECODER在PropertySheet属性对象中,查找name为decoder这个属性对应的value,这个value就是Decoder的实例对象,因为getComponent返回的是Configurable类型,所以进行了强制转换。
当然属性的类型不止这一种,还有int,String等,相应的查找方法就是getInt,getString,大家可以在PropertySheet这个类中进行详细查看。
今天先暂时介绍这些,总结一下:
sphinx4中,受配置文件管理的对象都实现了Configurable这个接口,在回调函数newProperties中,通过PropertySheet把它引用到的其他成员给传递进来,我们可以通过PropertySheet的getComponent,getInt等方法来获取这些成员的值。