使用服务

From Apache OpenOffice Wiki
Jump to: navigation, search



引入接口和服务的概念是出于以下几个原因:

接口和服务将规范从实现中分离出来

接口或服务的规范是抽象的,也就是说,它没有定义支持某项功能的对象如何在内部实现此支持。通过 OpenOffice.org API 的抽象规范,可以在 API 下分离出实现,并安装其他实现(如果需要)。


服务名称允许按规范名称而不是类名称创建实例

在 Java 或 C++ 中,使用 new 运算符来创建类实例。此方法有所限制:获得的类为硬编码。以后您无法在不编辑代码的情况下将其更换为其他类。服务的概念解决了这个问题。OpenOffice.org 中的中心对象工厂(即全局服务管理器)被请求创建一个对象,此对象不需要被定义内部实现就可以用于特定目的。这是可以实现的,因为通过服务名称可以从工厂定制服务,并且工厂决定返回的服务实现。获得哪种实现没有什么区别,因为您只使用明确定义的服务接口。


多继承接口使细颗粒状接口便于管理

如果抽象接口是细颗粒状,即小型且仅描述对象的一个方面而不是多个方面,则可以更好的重复使用。但那样的话,就需要多个此类接口来描述一个有用的对象。一方面,多继承接口允许具有细颗粒状接口;另一方面,又允许通过将接口组织成集合来轻松地管理这些接口。由于在办公软件环境中对象很可能共享多个方面,因此,此细颗粒状可以使接口重复使用,从而获得行为一致的对象。例如,可以使用统一的方式来处理文字,无论处理的是正文、文字框、页眉或页脚文字、脚注、表格单元格还是绘图形状中的文字。不需要为这些不同的文字处理定义单独的接口。


我们来看看 UML 表示法中的旧式服务 com.sun.star.text.TextDocument。下面的UML 图描述了 TextDocument 服务的强制接口。这些接口表现了 OpenOffice.org 中文本文档的基本方面。图中含有文字,可进行搜索和刷新。它是包含 URL 和控制器的模型,并且可进行修改、打印和存储。UML 图显示了如何在 API 中进行指定。

文本文档


左侧显示了服务 com.sun.star.text.TextDocumentcom.sun.star.document.OfficeDocument。每个 TextDocument 都必须通过定义包含这些服务。


右侧显示了服务必须导出的接口。其方法分层列出了各种接口中含有的方法。在 OpenOffice.org 中,所有接口的名称都必须以 X 开头,以区别于其他实体名称。


每个 TextDocument 都必须支持以下三种接口:XTextDocumentXSearchableXRefreshable。此外,由于 TextDocument 始终是 OfficeDocument,因此它还必须支持 XPrintableXStorableXModifiableXModel 接口。这些接口中含有的方法涉及:打印、存储、修改和模型处理等方面。


请注意,插图中显示的接口仅为 TextDocument 的强制接口。TextDocument 具有可选属性和接口,其中,必须支持 CharacterCountParagraphCountWordCount 属性以及 XPropertySet 接口(如果属性存在)。OpenOffice.org 中 TextDocument 服务的当前实现不仅支持这些接口,而且支持 所有可选接口。TextDocument 的用法在文本文档中进行了详细的介绍。


使用接口

由于必须通过 UNO 对象的接口来访问它们,因此会对某些语言(例如 Java 和 C++)造成影响。因 为在这些语言中,只有编译器所需的对象引用类型正确时才能从中调用方法。在 Java 或 C++ 中,在 访问对象实现的接口之前,通常就可以转换对象类型。但使用 UNO 对象时是不同的:必须, UNO 环境在需要访问对象支持的接口的方法时获得相应的引用,但编译器对此不知情。只有这时才能安 全地转换对象类型。


Java UNO 环境含有用于此目的的 queryInterface() 方法。它看起来似乎非常复杂,但当您了解了 queryInterface() 是与跨进程安全转换 UNO 类型相关的,就会很快习惯它。看一下第二个示例 FirstLoadComponent ,其中创建了一个新 Desktop 对象,然后使用 queryInterface 方法获取 XComponentLoader 接口。

  Object desktop = xRemoteServiceManager.createInstanceWithContext(
                "com.sun.star.frame.Desktop", xRemoteContext);
 
  XComponentLoader xComponentLoader = (XComponentLoader)
                UnoRuntime.queryInterface(XComponentLoader.class, desktop);


我们请求服务管理器使用其工厂方法 createInstanceWithContext() 创建 com.sun.star.frame.Desktop 接口。此方法定义为返回 Java 对象类型,您对此应不会感到意外,因为工厂必须能够返回任何类型:

  java.lang.Object createInstanceWithContext(String serviceName, XComponentContext context)


我们收到的对象是 com.sun.star.frame.Desktop 服务。


以下为 UML 表示法中的一个简单规范,显示与 com.sun.star.frame.Frame 服务及支持的接口之 间的关系。问题是,我们知道在工厂中定制的对象是 DesktopUnoUrlResolver,并从其他接口中导 出接口 XComponentLoader,而编译器却不知道。因此,必须使用 UNO 运行时环境请求或查询 XComponentLoader 接口,因为我们要使用此接口上的 loadComponentFromURL() 方法。queryInterface() 方法可以确保获得能够转换为所需接口类型的引用,无论目标对象是本地对象还是远程 对象。Java UNO 语言绑定中有两种 queryInterface() 定义:

  java.lang.Object UnoRuntime.queryInterface(java.lang.Class targetInterface, Object sourceObject)
  java.lang.Object UnoRuntime.queryInterface(com.sun.star.uno.Type targetInterface, Object sourceObject)


由于指定 UnoRuntime.queryInterface() 返回 java.lang.Object(与工厂方法 createInstanceWithContext() 相同),因此仍必须将接口引用明确地转换为所需的类型。不同之处在于,使用 queryInterface() 可以将对象安全转换为接口类型,而且最重要的是,引用现在甚至可以与另一个进程中的对象一起使用。以下是分步详解的 queryInterface() 调用:

  XComponentLoader xComponentLoader = (XComponentLoader)
                  UnoRuntime.queryInterface(XComponentLoader.class, desktop);

XComponentLoader 是我们要使用的接口,因此定义名为 xComponentLaoder(x 小写)的 XComponentLoader 变量,以存储 queryInterface 中的接口。


然后,查询 desktop 对象中的 XComponentLoader 接口(将 XComponentLoader.class 作为目标接口传入,并将 desktop 作为源对象传入)。最后,将结果转换为 XComponentLoader,并将生成的引用指定给变量 xComponentLoader。


如果源对象不支持查询的接口,queryInterface() 将返回 null。


在 Java 中,当引用的对象支持所需接口但引用类型不正确时,对 queryInterface() 的此调用是必需的。幸运的是,您不仅可以从 java.lang.Object 源类型调用 queryInterface(),而且还可以从其他接口引用查询接口,如下所示:

  // loading a blank spreadsheet document gives us its XComponent interface:
  XComponent xComponent = xComponentLoader.loadComponentFromURL(
  "private:factory/scalc", "_blank", 0, loadProps);
 
  // now we query the interface XSpreadsheetDocument from xComponent
  XSpreadsheetDocument xSpreadsheetDocument = (XSpreadsheetDocument)UnoRuntime.queryInterface(
                  XSpreadsheetDocument.class, xComponent);

此外,如果以此方式将方法定义为已经返回接口类型,则无需查询接口,但是却可以立即使用其方 法。在以上代码中,loadComponentFromURL 方法指定为返回 com.sun.star.lang.XComponent 接口,因此如果希望收到正在关闭文档的通知,可以直接在 xComponent 变量中调用 XComponent 方法 addEventListener() 方法和 removeEventListener() 方法。


C++ 中相应的步骤由 Reference<> 模板完成,该模板将源实例作为参数对待:

  // instantiate a sample service with the servicemanager.
  Reference< XInterface > rInstance =
  rServiceManager->createInstanceWithContext( 
  OUString::createFromAscii("com.sun.star.frame.Desktop" ),
  rComponentContext );
 
  // Query for the XComponentLoader interface
  Reference< XComponentLoader > rComponentLoader( rInstance, UNO_QUERY );


在 OpenOffice.org Basic 中,不需要查询接口,Basic 运行时引擎在内部可以完成相关操作。


随着多继承接口在 OpenOffice.org API 中的扩展,在 Java 或 C++ 中明确地查询特定接口的需求将越来越少。例如,用假定接口

  interface XBase1 {   void fun1();
  };
  interface XBase2 {
      void fun2();
  };
  interface XBoth { // inherits from both XBase1 and XBase2
      interface XBase1;
      interface XBase2;
  };
  interface XFactory {
      XBoth getBoth();};


您可以在通过 XFactory.getBoth() 方法获得的引用中直接调用 fun1()fun2(),而无需查询 XBase1XBase2


使用属性

一个对象必须通过那些允许您使用属性的接口来提供它的属性。这些接口最基本的形式为接口 com.sun.star.beans.XPropertySet。还有属性的其他接口,例如 com.sun.star.beans.XMultiPropertySet,它可以用单个方法调用来获取和设置多个属性。当服务中存在属性时,始终支持 XPropertySet


XPropertySet 中,有两种方法执行属性访问,这两种方法在 Java 中定义如下:

  void setPropertyValue(String propertyName, Object propertyValue)
  Object getPropertyValue(String propertyName)


在 FirstLoadComponent 示例中XPropertySet 接口用于设置单元格对象的 CellStyle 属性。该单元格对象是一个 com.sun.star.sheet.SheetCell,从而也支持 com.sun.star.table.CellProperties 服务,该服务具有属性 CellStyle。以下代码解释如何设置此属性:

  // query the XPropertySet interface from cell object
  XPropertySet xCellProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xCell);
 
  // set the CellStyle property
  xCellProps.setPropertyValue("CellStyle", "Result");

现在,您可以开始使用 OpenOffice.org 文档了。

Content on this page is licensed under the Public Documentation License (PDL).
Personal tools
In other languages