【colorado】
按语:本文是DPWI第4章的笔记。在3.3.1版的1~9章中与1.3.0版马维达先生中译本相应章节的内容基本相同,变化比较小,可以参考马维达先生的译本。 Slice 在客户与服务器之间建立合约,描述应用程序所使用的各种类型及对象接口。这种描述与语言实现无关。Slice 定义由编译器编译到特定的实现语言,编译算法称之为语言映射。编译器把与语言无关的定义翻译成针对特定语言的类型定义和API。开发者使用这些类型和API 来提供应用功能,并与Ice 交互。Ice 目前支持C++,Java, C#, Python,PHP,Ruby的语言映射。
例如: /* Printer Slice */ #ifndef SIMPLE_ICE #define SIMPLE_ICE
module Demo {
interface Printer { void printString(string s); //打印字符串 };
};
#endif Slice 关键字小写,只有Object、LocalObject首字母大写。 标识符大小写不敏感,不能有下划线。标识符必须保持拼写一致。以Ice开头的标识符被保留。将Slice关键字用作标识符,使用反斜线转义。如 /dictionary。
模块:Slice所有定义嵌套进模块中。 module ZeroC { module Client { // Definitions here... }; module Server { // Definitions here... }; }; 重新打开模块: module ZeroC { // Definitions here... }; // Possibly in a different source file: module ZeroC { // OK, reopened module // More definitions here... }; Slice 数据类型 类型 | 映射类型的范围 | 映射类型的大小 | bool | flase / true | ≥ 1位 | byte | -128~127 | ≥ 8位 | short | -215~215 | ≥ 16 | int | -231~231-1 | ≥ 32位 | long | -263~263-1 | ≥ 64位 | float | IEEE 单精度类型 | ≥ 32位 | double | IEEE 双精度类型 | ≥ 64位 | string | 所有Unicode字符,除了所有位为零的字符。 | 可变长度 |
Slice 提供了整数类型short、int,以及long,没有提供无符号类型。 Slice 串使用的是Unicode 字符集。唯一一个不能出现在串中的字符是零字符。
Slice 的byte 类型是一种(至少) 8 位的类型,当在地址空间之间传送时,它保证不会发生任何改变。
枚举: enum Fruit { Apple, Pear, Orange }; Slice没有定义枚举的顺序值。
结构: struct TimeOfDay { short hour; // 0 - 23 short minute; // 0 - 59 short second; // 0 - 59 }; Slice类型定义,除模块外不能嵌套;因此结构不能嵌套定义,但可以这样定义: struct Point { short x; short y; }; struct TwoPoints { // Legal (and cleaner!) Point coord1; Point coord2; };
序列:变长的元素向量 sequence FruitPlatter; sequence FruitBanquet;
词典:从键类型到值类型的映射 dictionary EmployeeMap; 词典的键类型无需为整型 dictionary WeekdaysEnglishToGerman; 不能使用浮点值或嵌套结构作键
接口: interface Clock { TimeOfDay getTime(); void setTime(TimeOfDay time); };
参数: 定义的操作既有输入参数,又有输出参数,输出参数必须放在输入参数的后面: void changeSleepPeriod( TimeOfDay startTime, TimeOfDay stopTime, out TimeOfDay prevStartTime, out TimeOfDay prevStopTime);
Slice 不支持既是输入、又是输出参数的参数。 Slice 不支持操作重载,同一接口中的各个操作必须具有不同的名称。
幂等操作:多次执行同一操作,结果不变,关键字idempotent interface Clock { idempotent TimeOfDay getTime(); idempotent void setTime(TimeOfDay time); };
用户异常:
exception Error {}; // 异常可以为空
exception RangeError { TimeOfDay errorTime; TimeOfDay minTime; TimeOfDay maxTime; };
interface Clock { idempotent TimeOfDay getTime(); idempotent void setTime(TimeOfDay time) throws RangeError, Error; }; 异常可以继承。在运行时,可以抛出任何与异常规范中列出的异常类型兼容的异常。 如果客户端不识别接收的派生异常,只识别基异常,就将接收的异常切成基异常。
Ice:Exception → LocalException → Run-time Exception ↘UserException
主要的运行时异常: a· ObjectNotExistException:找不到对象 b· FacetNotExistException:找不到层面 c· OperationNotExistException:找到服务者,但找不到操作。
服务器端错误产生的一般异常: UnknownUserException:抛出的Slice异常没有在异常规范中声明。 UnknownLocalException:上述a,b,c三种异常之外的运行时异常 UnknownException:非Ice异常,如C++异常。
代理: interface Clock { idempotent TimeOfDay getTime(); idempotent void setTime(TimeOfDay time); }; dictionary TimeMap; // 时区 — 时钟
interface WorldTime { idempotent void addZone(string zoneName, Clock* zoneClock); void removeZone(string zoneName) throws BadZoneName; idempotent Clock* findZone(string zoneName) throws BadZoneName; idempotent TimeMap listZones(); idempotent void setZones(TimeMap zones); }; Clock* —> 接口* —> 代理:类似C++对象指针 * 称为代理操作符,*号左边必须是接口/类
接口继承: interface AlarmClock extends Clock { idempotent TimeOfDay getAlarmTime(); idempotent void setAlarmTime(TimeOfDay alarmTime); }; 接口可以多继承: interface RadioClock extends Radio, AlarmClock .... 多个接口不能含有同名操作。即如果Radio中有set操作,AlarmClock中有set操作,则 RadioClock不能从两个接口继承。
所有接口最终都派生自Object。 Ice支持null代理。 不要定义空接口,在设计上是错误的。
类: 类允许你在客户端实现行为,而接口只允许你在服务器端实现行为。 不要定义空类,在设计上是错误的。
class TimeOfDay {...} class DateTime extends TimeOfDay {...} 类只支持单继承,下面的定义是错误的: class DateTime extends TimeOfDay, Date {...} 派生类不能重新定义基类数据成员。
类的操作是本地操作,调用类上的操作并不会产生远程过程调用。在线上传输类时,Ice运行时只整编类的数据成员。接收者在自己的地址空间里实例化这个类,负责为类提供操作的实现代码。即提供一个类工厂。
要记住,一旦你使用了有操作的类,你实际上就是在使用客户端原生代码,因此,你不再能享受到接口所提供的实现透明性。建议最好使用接口和没有操作的类。
class Clock implements Time {...} 类实现接口 class RadioClock implements Time, Radio {...} 类实现多个接口 class RadioAlarmClock extends Clock implements AlarmClock, Radio {...}类继承及实现 类不能重定义基接口或基类继承的操作或数据成员。
interface Example { TimeOfDay* get(); }; get返回TimeOfDay类代理。客户可以通过这个代理调用操作,但不能访问数据成员。这是因为代理没有数据成员的概念。
定义操作时,将接口作为参数,使得接口以传值方式传递。由于接口在实现时是抽象的,因此实参应该传入实现接口的类。
提前声明: interface Time; class TimeOfDay;
类型ID ::MyModule::Child;
Object的操作 ice_ping 测试某个对象是否可到达 ice_isA 测试目标对象是否支持指定的类型 ice_id 接口的派生层次最深的类型ID ice_ids 含有某个接口所支持的所有类型ID的序列
本地类型: local关键字定义了只在本地访问的API。Slice 编译器不会为相应的类型生成整编代码。这意味着,本地类型永远不能从远程访问,因为它不能在客户和服务器之间传送。
local 主要用于Ice运行时的各种API。
名字与作用域: 如果两个标识符只有大小写不同,将被认为是相同的。Slice 编译器还要求你在使用标识符时,始终使用同样的大小写。否则会产生编译错误。
元数据指令: ['java:type:java.util.LinkedList'] sequence IntSeq; 指示编译Java程序时,使用LinkedList表示序列。
全局元数据指令: [['java:package:com.acme']] 所有使用本Slice定义的Java程序,引入包名com.acme
废弃的Slice定义: ['deprecated:.....'] 冒号跟着警告消息,可忽略。
Slice检查和: 检查C/S两端的Slice定义是否一致: #include interface MyServer { idempotent Ice::SliceChecksumDict getSliceChecksums(); // ... };
词典类型:dictionary SliceChecksumDict; 词典中每个元素的键是一个Slice类型ID,并且值是该类型的检查和。
|