急!能否请版主关注一下:我想在程序运行当中对我自定义的类动态添加属性,不知道能否实现?观看详情请进。(300分)

  • 主题发起人 主题发起人 南京男生
  • 开始时间 开始时间

南京男生

Unregistered / Unconfirmed
GUEST, unregistred user!
问题具体如下:
我自己设计了几个图元类,比如一个电器开关,我已经能做到在程序运行时修改其属性了,但是
我想希望能在程序运行时动态的增加其属性。比如:我在源代码设计阶段已经实现了电器开关的color,
width等属性;程序编译后,假如用户要求要填入“最大通过电流”,设为I,而我在设计阶段并没有电流I
这个属性,那么,我能不能实现用户通过某个对话框,给电器开关类添加一个“电流I”属性?
之所以这么想,这样子的话我就可以不去修改源代码而增强软件的扩充性。我自己思考过,理论上似乎
不能实现,Delphi的编译系统可以管理类,而脱离了Delphi的我的程序能实现类的管理吗?应该不可能。而
delophi的RTTI似乎只能动态修改,而不能动态添加。
我该怎么办呢?老老实实改程序?千万不要告诉我说:用数据库或文件记录一下,再进行关联(因为有好多个
类)。当然,如果有高招,请不吝赐教。
请各位大侠指点迷津,因为这个问题涉及到我的一个系统的设计,我的工作停顿下来了,并等候各位。先谢了!

 
其实请各位进来发发言也未尝不可!
 
这个是GIS的概念啊!图形属性数据库啊!好好看看这方面的资料吧!如果系统大的话可以用
AUTOCAD的2次开发工具
 
我用类似下面的方法, 可以动态扩充一个设备的部件, 不知道对你有没有帮助?
TDevice = class(TObject)
public
procedure Add(aDev: TDevice);
procedure Remove(aDev: TDevice);
property Owner: TDevice read FOwner;
property Items[idx: Integer]: TDevice read getItems write setItems; default;
end;
 
你可以更具你可能增加的属性类型先定义几个数组,比如说,可能增加 string 和 Double
型的属性,可以现在你的类中添加两个动态数组:

ary_str : array of string;
ary_dbl : array of Double;

然后在实例该类的时候给两个数组设定初始长度
在增加方法:
procedure add_ary_str_item();
procedure del_ary_str_item();
procedure add_ary_int_item();
procedure del_ary_int_item();
注意在方法处理数组的长度,这样就可以实现属性的动态添加和删除;
 
如果是简单处理的话用个大数组就可以了!这个也未尝不可!不过速度方面。。。
 
速度绝对没问题,主要是要注意处理数组的长度,别的都没什么难的
 
首先谢谢各位!
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


 
这要看你增加的临时属性是不是需要保存,不过如果保存到数据库的话,那也可以将每种
属性当作一条记录来操作,比如增加一个属性,就将相应得属性名称和属性值以及属性类型
等保存到数据库中,反之,减少一个属性,删除相应的数据库记录就ok了,许多财务系统中
都有相应的科目设置,就是用的这种方式;而且可以根据你添加的属性内容,更改相应的
其它相关表的结构,不过可能需要你在alter表结构的时候,注意数据类型、数据长度等
细节;
 
就这样 吧!散分了!
 

Similar threads

D
回复
0
查看
825
DelphiTeacher的专栏
D
D
回复
0
查看
831
DelphiTeacher的专栏
D
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部