高手请进:请教对象存储解决方案 (100分)

A

Adnil

Unregistered / Unconfirmed
GUEST, unregistred user!
设计一个类例如
TProject = class
private
FModified: boolean;
public
property1: sometype1;
property2: sometype2;
property3: sometype3;
.....
propertyn: sometypen;
procedure LoadFromFile;
procedure SaveToFile;
end;

procedure TProject.LoadFromFile;
begin
loadproperty1;
loadproperty2;
...
loadpropertyn;
end;

procedure TProject.SaveToFile;
begin
saveproperty1;
saveproperty2;
...
savepropertyx
//如果propertyx自从读入以后并没有改动过,那么对propertyx的保存就不必要了
...
savepropertyn;
end;
Project经过Load之后,程序界面中对Project对象的每个属性进行显示,用户可对属性进行修改。
现在问题来了,如果用户之修改了其中的一个属性PropertyX,那么这个Save过程该如何写?
如果采用将所有的属性都重新存储一遍的方法则存储比较耗时(例如要经过TCP/IP连接存储到服
务器的一个文件的情况),如果只对PropertyX进行覆盖存储,则需纪录每个属性是否经过改变标记,
类会变得很大。

请问是否有一个较好的解决方法?
 
G

guouse

Unregistered / Unconfirmed
GUEST, unregistred user!
参照以下:
unit Golbals;
interface
type
TCurrentUser = class
private
FUseId:String;
FUseName:String;
FDepart:String;
FUseLogin:String;
FUseAll:String;
FUseSelect:String;
FUseInPut:String;
FUseEdit:String;
FUseDelete:String;
FUseSpecial:String;
FUseMain:String;
FUseManager:String;
FUseShift:String;
FPalace:String;
// FUseOther:String;
{ Private declarations }
public
{ Public declarations }
Property UseId:String Read FUseId Write FUseId;
Property UseName:String Read FUseName Write FUseName;
Property Depart:String Read FDepart Write FDepart;
Property UseAll:String Read FUseAll Write FUseAll;
Property UseLogin:String Read FUseLogIn Write FUseLogin;
Property UseSelect:String Read FUseSelect Write FUseSelect;
Property UseInput:String Read FUseInput Write FUseInput;
Property UseEdit:String Read FUseEdit Write FUseEdit;
Property UseDelete:String Read FUseDelete Write FUseDelete;
Property UseMain:String Read FUseMain Write FUseMain;
Property UseManager:String Read FUseManager Write FUseManager;
Property UseSpecial:String Read FUseSpecial write FUseSpecial;
Property UseShift:String Read FUseShift write FUseShift;
Property Palace:String Read FPalace write FPalace;
end;
Var
CurrentUser:TCurrentUser;
implementation
initialization
CurrentUser:=TCurrentUser.Create;
end.
//调用
uses Golbals;
//*save
With Dm.PassWordTab do
Begin
Open;
if FindKey([IdEdit.Text,Dm.Encrypt(ShiftEdit.Text,En_Key)]) Then
Begin
CurrentUser.UseId:=FieldByName('IdCode').Value;
CurrentUser.Depart:=FieldByName('Depart').Value;
CurrentUser.UseName:=FieldByName('IdName').Value;
CurrentUser.UseLogin:=FieldByName('UseLogin').Value;
CurrentUser.UseInput:=FieldByName('UseInput').Value;
CurrentUser.UseEdit:=FieldByName('UseEdit').Value;
CurrentUser.UseSelect:=FieldByName('UseSelect').Value;
CurrentUser.UseDelete:=FieldByName('UseDelete').Value;
CurrentUser.UseSpecial:=FieldByName('UseSpecial').Value;
CurrentUser.UseManager:=FieldByName('UseManager').Value;
CurrentUser.UseMain:=FieldByName('UseMain').Value;
CurrentUser.UseAll:=FieldByName('UseAll').Value;
CurrentUser.UseShift:=ComBoBox1.Text;
DateStr:=FormatDateTime('yyyymmdd',DateTimePicker1.Date);
DateStr:=Copy(DateStr,1,4)+'/'+Copy(DateStr,5,2)+'/'+Copy(DateStr,7,2);
CurrentUser.UseDate:=DateStr;
CurrentUser.Palace:='myuse';
DStr:=FieldbyName('Depart').Value;
PassWordForm.ModalResult:=MrYes;
end
//*
//* load
Edit1.text=Currentuser.Palace
 
Y

yhaochuan

Unregistered / Unconfirmed
GUEST, unregistred user!
http://www.isunsoft.net/forum/link.asp?TOPIC_ID=205
 
C

creation-zy

Unregistered / Unconfirmed
GUEST, unregistred user!
>>如果只对PropertyX进行覆盖存储,则需纪录每个属性是否经过改变,类会变得很大
你可以参考一下:
来自:caidaoli, 时间:2002-1-21 20:41:00, ID:875087
完全可以用他的方案,用一个通用的过程获得所有属性的值,自动判断是否发生了变化,
开销并不大的。
 
A

Adnil

Unregistered / Unconfirmed
GUEST, unregistred user!
yhaochuan你的链接不太对,我的这里的属性是自定义保存和读取,跟Delphi利用RTTI信息
读写dfm文件不同。
 
Y

yhaochuan

Unregistered / Unconfirmed
GUEST, unregistred user!
但我怎么看你写的都象是Delphi控件。
 
A

Adnil

Unregistered / Unconfirmed
GUEST, unregistred user!
To yhaochuan:
Delphi控件是Delphi对象的扩展,增加了publish段的属性,这些属性Delphi会在界面设计
的时候自动维护在*.dfm文件中,编译时候自动加入Exe文件里面,Exe执行的时候读取二进
制dfm资源信息,自动创建对象,并给对象的属性赋值。
 
Y

yhaochuan

Unregistered / Unconfirmed
GUEST, unregistred user!
你还是没说明白,将DFM文件编译加入EXE,本来就是Delphi做的嘛。
 
A

Adnil

Unregistered / Unconfirmed
GUEST, unregistred user!
To yhaochuan:
不明白你是真不懂还是假不懂,我什么时候说过我要把对象存入dfm里面?
我这里的Load和Save是把信息从数据库或者文件读入到对象中,或者将对象
信息保存到数据库或者文件中,跟dfm有什么关系?
 
Y

yhaochuan

Unregistered / Unconfirmed
GUEST, unregistred user!
private
procedrue setsometype1(value:string);
function getsometype1:string;
public
property1: sometype1:string read Getsometype1 write Setsometype1

implementation

TXXX.setsometype1(value:string);
begin
if value <> Fsometype1value then
Fsometype1value := value
//save this value to TXT file or save to sql server

end;
TXXX.getsometype1:string;
begin
//code get value(may be read from txt or read from SQL serve
end;

这可以做到你的要求吗?
 
Y

yhaochuan

Unregistered / Unconfirmed
GUEST, unregistred user!
写完property1: sometype1:string read Getsometype1 write Setsometype1
这句后按ctrl+shift+C
delphi会自动写出过程、函数的框架(就是下面这些了)。就不用自己一个一个code了。
procedrue setsometype1(value:string);
function getsometype1:string;


 
A

Adnil

Unregistered / Unconfirmed
GUEST, unregistred user!
TXXX.setsometype1(value:string);
begin
if value <> Fsometype1value then
Fsometype1value := value
//save this value to TXT file or save to sql server
end;
类似这样能够满足要求,但是开销太大了,修改一个属性就需要保存一下,如果每次
保存对需要对远程服务器进行连接,那如果修改了X个属性就需要对服务器连接X次,会很慢。

我想象中setsometype1过程中不应该包含保存过程,仍然放在Save过程中,这样也比较
符合面向对象设计。
然而Save过程框架就不好写了,类似如下的东东(效率肯定是最佳的):

procedure TProject.SaveToFile;
begin
打开设备 //设备泛指文件,数据库等
if property1Modified then
saveproperty1;
if property2Modified then
saveproperty2;
...
if propertyxModified then
savepropertyx;
...
if propertynModified then
savepropertyn;
关闭设备
end;
类中要记录太多的修改标记,faint
 
Y

yhaochuan

Unregistered / Unconfirmed
GUEST, unregistred user!
我想只有两种方法了,一是每次属性改变时都保存,
一是做许多BOOL变量给每个属性,用于判断此属性值有没有修改过,
还有一种是我随想:
为每个属性建立一个保存属性的过程,再申请一数组。
当setsometype1value(value:string)过程调用时将相应的保存属性的过程入口保存到此数组中
这样在saveproperty方法中,逐个运行此数组中的过程。
 
F

flier

Unregistered / Unconfirmed
GUEST, unregistred user!
Delphi中实际上提供了对象的序列化机制,TPersistent类就是实现的核心
对Published段的属性,可以通过RTTI动态枚举并保存,对自定义的字段,
可以通过TPersistent.DefineProperties进行定义,用于读写
而在序列化时,可以直接用TWriter.WriteComponent以及对应的TReader
的方法一次把一个Component写入/读出一个流,VCL会自动处理所有
published类型字段以及自定义字段的读写,当然类型有一定限制
具体使用方法看看Delphi的帮助好了,这里不罗嗦了……
下面是一个Delphi帮助里的例子,应该有帮助的说
procedure TSampleComponent.LoadCompProperty(Reader: TReader);
begin
if Reader.ReadBoolean then
MyCompProperty := Reader.ReadComponent(nil);
end;

procedure TSampleComponent.StoreCompProperty(Writer: TWriter);

begin
Writer.WriteBoolean(MyCompProperty <> nil);
if MyCompProperty <> nil then
Writer.WriteComponent(MyCompProperty);
end;

procedure TSampleComponent.DefineProperties(Filer: TFiler);

function DoWrite: Boolean;
begin
if Filer.Ancestor <> nil then { check Ancestor for an inherited value }
begin
if TSampleComponent(Filer.Ancestor).MyCompProperty = nil then
Result := MyCompProperty <> nil
else if MyCompProperty = nil or
TSampleComponent(Filer.Ancestor).MyCompProperty.Name <> MyCompProperty.Name then
Result := True

else Result := False;
end
else { no inherited value -- check for default (nil) value }
Result := MyCompProperty <> nil;
end;
begin
inherited
{ allow base classes to define properties }
Filer.DefineProperty('MyCompProperty', LoadCompProperty, StoreCompProperty, DoWrite);
end;
 
A

Adnil

Unregistered / Unconfirmed
GUEST, unregistred user!
这样受到的束缚也太多了,还是得应用RTTI这些高级技术,同时受到很多局限,假设两种情况:
1.propertyx中保存的是一个文件名,Project保存的时候要对这个文件进行修改如何处理?
2.程序如果移植,转用Visual Basic那又怎么办?

我需要的最好是一个通用的解决方案,而并非一定要利用语言的特性,这样束缚太多。
 
F

flier

Unregistered / Unconfirmed
GUEST, unregistred user!
首先,RTTI不是什么高级技术,象Delphi/Java这种运行期语言,RTTI是基础
无论你天天用到的IDE还是VCL,里面都有大量的RTTI的使用。
其次,一个语言封装的层次越高,其可移植性就越差,如果你要可移植性好
去看看《设计模式》好了,里面有专门的模式处理这种情况,不过代码需要手写。
需要手工写就失去了Delphi这种第四代语言的优势,代码易错且功能不完备。
最后,你所提的文件的问题,完全可以通过自定义属性的方式解决,问题都是有
解决方法的,关键在于你想不想去找。
 
A

Adnil

Unregistered / Unconfirmed
GUEST, unregistred user!
不明白你在说什么,一个良好的设计是语言和开发平台无关,我把框架设计完成了,
代码可以用各种不一样的语言来开发。
再者:我这里的原本目的也并非一定要将property1..propertyn进行保存,只是要判断这些
属性是否有过修改,如何进行修改标记的问题,保存的时候只需访问被用户修改过的属性。
我换一下题目吧,如果用标准C++语言实现。
 
F

flier

Unregistered / Unconfirmed
GUEST, unregistred user!
良好的设计的确是语言平台无关的,但4GL语言的突出特点并不是让你去做什么良好设计
开发效率是其第一位的,通过语言本身提供的机制能够快速、高效、稳定地实现用户
需求才是最重要的,自己开发的所谓设计,即使设计良好,实现高效,也会有各种潜在风险存在
回避这种表现欲,而使用现有的稳定的实现是商业软件开发和作法式开发的重要不同点
当然,你如果只是出于学习目的例外,否则建议尽量使用经过经验的商业代码
你的标题是寻求解决方案,并不是寻求设计方案,否则我的回答不会是这个思路……
 
A

Alongsun

Unregistered / Unconfirmed
GUEST, unregistred user!
[blue][/blue]全是废话!没有 一个敢说自己是老大的,你们为什么不去看看我的问题,我问了一年了!没有
人回答真让我感觉到这里的技术是不是已经过时了,或者是这是这里的人已经不
是做编程的!
http://www.delphibbs.com/delphibbs/dispq.asp?lid=719446
http://www.delphibbs.com/delphibbs/dispq.asp?lid=666070
http://www.delphibbs.com/delphibbs/dispq.asp?lid=716037
http://www.delphibbs.com/delphibbs/dispq.asp?lid=730641
http://www.delphibbs.com/delphibbs/dispq.asp?lid=655233
如果能有人回答这些问题才是真的高手呀!
 
F

flier

Unregistered / Unconfirmed
GUEST, unregistred user!
to Alongsun:
首先,你的问题有的小得翻翻书就可以回答,有的大得可以写本书。
其次,这里回答问题都是义务性质的讨论,没有人该着你。
最后,虽然你的几个问题我都可以解答,但我不是什么高手,
也不想当什么高手,但你不要小看这里的人。没人回答你的问题
是有原因的,先看看你自己的问题,再去嘲笑别人。

btw:问问题是向别人请教,最好虚心一点,冲你的态度我就懒得回答。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
947
SUNSTONE的Delphi笔记
S
S
回复
0
查看
768
SUNSTONE的Delphi笔记
S
I
回复
0
查看
589
import
I
顶部