首先谢谢各位!
to tseug:你的方法能不能实现属性和属性值的自动存贮?
to zhai_xin:用动态数组的话,我们还是得用数据库存储其属性及其值吧。
譬如我再捎带问一下:静态属性中的Default 值是不是客户程序代码在编译时将固定的赋值
语句编译进了exe文件?
另外,我自己找了这么一篇文章,和我的目的是一致的,但其思路限于我水平,看得不明不白,
请各位大侠帮我诊断一下:
动态属性(一)
几乎我们碰到的所有对象都有属性,通常我们会在设计时(Design Time)在一个类里面对属性进行声明,这叫做静态属性(Fixed Property)。绝大多数情况下这样就足够了,但是如果需要大量的属性,并且需要频繁的改动,并且这些改动可能发生在运行时(Run Time)的话,静态属性就不能满足要求了。这迫使我们使用多种类型的动态属性。所有的动态属性都有这样一个共性:用一个带参数的查询方法获取属性。
静态属性
静态属性最关键的是他在设计时就被固定了,并且在运行时它的所用实例都必须遵循这个决定。在一些情况下,这是一个麻烦的限制。假如我们要设计一个通讯录,其中有些属性是固定的,比如家庭地址,家庭和工作电话,Email。但每个实例都稍有不同,有人需要记录父母的地址,有人可能有兼职工作的电话。要想把所有情况都预料到几乎是不可能的。如果修改程序的话,就必须经过编译,测试,发布这么一整套流程。在这种情况下就需要使用动态属性。
我们将要讨论动态属性的好几个变种,他们的差异在于对灵活性和安全性的不同权衡。
Flexible Dynamic Property 是最简单的一种模式。
Flexible Dynamic Property
提供一个以String为参数的Attribute 仅仅用String就能定义一个属性。
这个模式的本质是:在Person上增加一个Qualified关联,关键字(Key)是一个简单值,通常是String。如果要为person Kent增加一个vacation address属性,只需用code list3 的代码,不必重新编译Person 类,甚至可以从GUI或者文件读取要增加的属性,这样连客户代码也不用重编译了。
class person {
public object getValueOf( String key );
public void setValueOf( String key, object value );
}
code list2
kent.setValueof( “VacationAddress”, anAddress);
Address kentVacationAddress = ( Address ) kent.getValueOf( “vacationAddress” )
code list3
既然Dynamic Property具有这样的灵活性,那么我们为什么还要使用Fixed Peoperty呢?其实灵活性是有代价的, Dynamic Property 牺牲了软件各部分之间依赖关系的清晰性。你可以非常方便的为一个Person对象加上vacation address 属性,但以后我怎么得到它呢?如果使用Fixed Property 只需要察看Person类的接口,就能知道它的所有属性。并且编译器会帮你检查哪些能做哪些不能做。而使用了Dynamic Property将失去设计时检查,Person 的接口更加难以确定,不仅要看在Person类里面定义了哪些接口,还要到代码里去察看加入了哪些Dynamic Property(通常它们根本就不在Person类里面),把它们发掘出来。
不光是属性难以查找,它使得依赖关系简直像噩梦一般。当我们使用Fixed Property的时候,客户代码 仅仅依赖于Person类,这种关系很容易跟踪。比如你改变了属性的名字,编译器会告诉你哪些代码需要修正。但是Dynamic Property会产生对任意某段代码的依赖性。它可能会是客户根本就不可见的某个类里的一段代码。如果有人改变了关键字字符串(Key String)会怎么样?如果有人改变了关键字字符串对应对象的类型又会怎么样?现在编译器帮不上你的忙,你甚至不清楚这些潜在的改变该从何找起。
这些问题在Flexible Dynamic Property 模式中表现得最严重。属性可以在设计时由Person的任何客户代码来创建。如果其他的客户代码使用了这个属性,那么这两个客户类之间产生了依赖关系,并且这种依赖很难被发现。属性还可以在运行时通过GUI或从文件添加。我们根本不可能在运行时确定哪些是Person合法的属性,当然我们可以向Person询问是否有一个属性叫做vacation address,假设不存在这个属性,那么到底是说明Person 没有表达vacation address的属性,还是说明Person没有一个叫 vacation address的属性?即使这个属性现在不存在,也不能说明过了一会这个属性是否会出现。
Flexible Dynamic Property 还有一个关键的缺点,要把属性由存储数据改变为操作很困难。对象的封装的一大好处就是,使用属性的客户根本不知道属性是对象中存储的数据,还是由某个方法计算得到。这是一种面向对象的重要方法。当存在子类化的时候,可以在超类中存储数据,而在子类里进行计算,反之亦然。当你使用的是动态属性,要将存储数据改为计算值,只能在动态属性的通用获取方法中加入代码(Code List4)。这样的代码显得很脆弱,而且难于维护。
class Person {
public Object getValueOf(String key) {
if (key = “vacationAddress”) then return calculatedVacationAddress();
if (key = ”vacationPhone”) then return getVacationPhone();
// else return stored data
动态属性的改进形式将帮助你解决以上问题,当然不可能是全部问题。动态属性最本质的缺点在于降低了接口的清晰性,缺少设计时检查。不同动态属性提供了不同的运行时检查能力,唯一的问题是在运行时提供的接口清不清晰,能提供多少运行时检查。对于Flexible Dynamic Property这两项都达不到要求。
动态属性经常用在数据库相关的应用中,因为改变数据库的定义是一件很痛苦的的事情,特别是那些涉及到大量的数据迁移的情况。像Corba这样的分布式对象接口,因为类似的原因也会用到动态属性,大量的远程客户使用这些接口,动态的改变在所难免。在这来两种情况下,设计时和运行时没有明显的区分。
带定义的动态属性(Defined Dynamic Property)
提供一个以某一对象作为参数的属性,要定义一个属性就要创建一个新的对象实例。
为了增加运行时的检查,第一步就是使用带定义的动态属性(Defined Dynamic Property)。它与Flexible Dynamic Property的本质区别在于,动态属性的关键字不再是任意的字符,而是一个类的实例。(Figure 3)
Figure3 Defined Dynamic Property
从表面上看使用Defined Dynamic Property并没有多大变化,事实上接口几乎是一样的。(Code List5 Code List6)只不过关键字不再是任意的,而是受到Contact Type实例的约束。我们仍然能够在运行时添加属性,只不过要创建一个新的Contact Type实例。现在至少有一个地方可以得到可用的关键字的列表,而不用遍历整个程序代码。
现在你可以建立一些检查来避免读取不存在的属性这样的错误(Code List7),我会抛出未检查错误(unchecked exception),因为我认get()方法的先决条件(preconditon).应该是客户提供合法的Contact Type 名字。客户可以通过使用hasInstanceNamed()方法进行先决条件检查。很多时候客户代码会坚持使用Contact Type对象,而不是字符串。
通常Contact Type会被放到一个字典里,这个字典一般用字符作为索引。这个字典可以是Contact Type 的静态字段(Static Field)。
class ContactType {
public static ContactType get(String name) {
if (! hasInstanceNsmed(name)) then throw new IllegalArgumentException(“no”);
// return Contact Type
}
CodeList 7 Checking use legal Contact Type
Defined Dynamic Property已经能为我们提供多得多的关于属性的信息,但它仍然是无类型的,我们并不能强制vacation address属性中一定是存入Address类型的数据。Typed Dynamic Property在这个方面做了改进。
带类型的动态属性(Typed Dynamic Property)
提供一个以某一对象作为参数的属性,要定义一个属性就要创建一个新的对象实例,并且指定属性的值类型。
Figure 5 Model for typed dynamic propery using qualified association
Typed Dynamic Property在Defined Dynamic Property 的基础上添加了属性的类型信息(figure 5,figure6)现在Contact Type的实例不仅指明Person对象理有哪些属性,而且指明这些属性的类型
class Person {
public Object getValueOf(ContactType key);
public void setValueOf(ContactType key, Object value)
class ContactType {
public Class getValueType();
public ContactType(String name, Class valueType);
Code List 8
class Person {
public getValueOf(ContactType key, Object value) {
if (! key.getValueType.isInstance(value))
throw new IllegalAgumentException(“Type Error”);
// set the value
Code List 9
做这样的类型检查可以帮助我们避免错误,但还是不如静态属性清晰。这些检查是在运行时,而不是在设计时,这样就降低了有效性。无论如何比起完全没有类型检查要好得多了,特别当我们是在一个强类型的环境里。
待续:
1. reflect
2. seperate property
3. dynamic property with multi-valued associations
4. typed relationship
5. knowledge level in dynamic property