自认在OOP方面有造诣的请进,回答得了再给100分 ( 积分: 10 )

  • 主题发起人 publicnews
  • 开始时间
P

publicnews

Unregistered / Unconfirmed
GUEST, unregistred user!
每本书都在吹嘘OOP,每个人都在吹嘘OOP,但在我见过的别人源码中,对于数据维护的实现基本上都是先定义一个父窗体,在其中定义一些Edit,Delete什么的方法,然后在具体的数据窗体(如雇员资料)中做相应的数据校验等逻辑处理.
看起来使用了继承,但这样就OO了吗?界面和业务根本没有分开,那些纸上谈兵的定义雇员对象的OO方法又应用在了哪里,似乎没有几个人知道.
那些自认OO方面有造诣的高手们又是如何应用的呢,给个应用实例让俺明白了重谢100分,不够再加

加以补充一下:
-----------------------------------------------------------------
我本来用的就是窗体继承,但虽然是窗体继承代码和界面也仍然在一起呀,举个例子,如果现在要改三层架构,那我的业务不就剥离不出来了?
 
每本书都在吹嘘OOP,每个人都在吹嘘OOP,但在我见过的别人源码中,对于数据维护的实现基本上都是先定义一个父窗体,在其中定义一些Edit,Delete什么的方法,然后在具体的数据窗体(如雇员资料)中做相应的数据校验等逻辑处理.
看起来使用了继承,但这样就OO了吗?界面和业务根本没有分开,那些纸上谈兵的定义雇员对象的OO方法又应用在了哪里,似乎没有几个人知道.
那些自认OO方面有造诣的高手们又是如何应用的呢,给个应用实例让俺明白了重谢100分,不够再加

加以补充一下:
-----------------------------------------------------------------
我本来用的就是窗体继承,但虽然是窗体继承代码和界面也仍然在一起呀,举个例子,如果现在要改三层架构,那我的业务不就剥离不出来了?
 
我来说两句
在公司软件开发中,需要用到串口
又要使用VB来制作界面
数据的最终处理方法是相同的
只不每种硬件的具体通讯协议不同
准备实现插件功能,不同的硬件使用不同插件
于是决定开发一个ActiveX控件嵌入到VB中,然后在ActiveX中实现根据不同设置调用不同插件
但是为了实现上层软件的通用化,又想简化编程及后期维护工作
所以决定使用导出类来实现
首先定义一个基类,包含了通用的类型定义,功能纯虚函数
这样在VB中的ActiveX控件只就知道,所有的插件都是断承自这个基类的
也就是说它只要根据相应的功能调用函数就可以了
具体的功能会在插件中完成
这样只要是从基类派生出来的子类都可以做为插件使用
 
OO是为了代码重用。界面和业务分开为了代码维护和减轻依赖关系。
虽然你说的那种方式我不认为是好方法,但是对于面向对象来说,你可以想想,我在基类里面的Edit,Delete里面放些公共的代码,工作量小了,将来修改全部这些窗体的一个比如Edit之前的一个行为,我还是工作量小了。只改基类。
对于模式的出现是一种面向对象的实践中一种总结。
对于大的工程维护,现在所提的Mvc实现业务逻辑层、表现层、控制层的分离,大大降低
维护的工作量。并且清晰。
 
1. OOP是让人使用的, 是为了让人解决问题方便、形象、可靠的;
2. 最重要的是OOP不是拿到这里来这样嘴上说的....
 
今天你OOP了吗?
 
我自己也感覺到確實是這樣啊。
得更深層次學習才行。
 
我开发软件的时候就是尽量使用 OOP,不说逻辑业务层面,至少是功能层面。这样特别是对于比较大的项目有很多好处,无论是开发还是改变整个系统的架构

以下列出一些供参详:
(1)定义一个项目通用功能类对象,根据不同类型的系统扩展其子类

对于同样的方法,不同的继承子类有不同的实现程序,但是调用定义是一样的,这样对于不同架构的程序模块移植和重复使用有很大帮助。

TfgGlobalFunction_bas //顶级基类
|—TfgGlobalFunction_ADO //ADO项目类
| |—TfgGlobalFunction_ADO_Access //ADO+Access数据库项目类
| |—TfgGlobalFunction_ADO_MSSQL //ADO+SQLServer数据库项目类
|
|—TfgGlobalFunction_BDE //BDE项目类
| |—TfgGlobalFunction_BDE_Access //BDE+Access数据库项目类
| |—TfgGlobalFunction_BDE_MSSQL //BDE+SQLServer数据库项目类
|
|—TfgGlobalFunction_Midas //Midas项目类
| |—TfgGlobalFunction_Midas_Server //Midas服务端类
| |—TfgGlobalFunction_Midas_Server_ADO //Midas ADO 服务端类
| |—TfgGlobalFunction_Midas_Server_ADO_MSSQL //Midas ADO+SQLServer服务端类
| |—TfgGlobalFunction_Midas_Server_ADO_Access //Midas ADO+Access服务端类(缺)
| |—TfgGlobalFunction_Midas_Server_BDE //Midas BDE 服务端类
| |—TfgGlobalFunction_Midas_Server_BDE_MSSQL //Midas BDE+SQLServer服务端类
| |—TfgGlobalFunction_Midas_Server_BDE_Access //Midas BDE+Access服务端类(缺)
| |—TfgGlobalFunction_Midas_Client //Midas客户端类

对于 TfgGlobalFunction 中可以放很多方法,比如:
Form_XXX //关于窗体(调用、显示、查找、关闭等)
DB_XXX //关于数据库(连接、访问等)
Sys_XXX //关于系统
Help_XXX //关于帮助
Permit_XXX //关于权限
Ref_XXX //关于引用
Receipt_XXX //关于编码
Report_XXX //关于报表
Publish_XXX //关于发布
Upgrade_XXX //关于升级
Print_XXX //关于打印
Language_XXX //关于多语种

(2)具体项目的时候再根据项目架构要求实例化不通的类作为一个全局功能对象,当然有可能对于不的项目具体一些方法需要Override

type TfgGlobalFunction=class(TfgGlobalFunction_define)
……
end;

var Global_Funs:TfgGlobalFunction;

(3)所有窗体都继承一个自己定义的窗体类,并且在窗体实例化时把在工程已开始就实例化的全局功能作为当前窗体一个方法指针,那么可以在任何窗体中都可以调用自身的一个子对象访问全局功能对象

集中在窗体类中的公共功能可以包括

//-------------------------
//窗体类
TMyForm=class(Tform)
……
Funs:TfgGlobalFunction;
end;

constructor TMyForm.Create(Owner:TComponent);
begin //构造函数
inherited Create(Owner);
Funs:=Global_Funs
//全局功能对象指针
……
end;

//-------------------------
//具体一个窗体

type TForm1=class(TForm)
……
end;

修改为
type TForm1=class(TMyForm)
……
end;

(4)对于各功能窗体的调用函数都可以直接定义在全局类 TfgGlobalFunction 里面,这样所以窗体间的互相调用基本上都不用用 uses 来引用,完全调用自身的 Funs 对象就可以调用其他窗体
 
致plenilune168:
听大侠一点拨,茅塞顿开
不过中间一些具体的实现还不是太明白,可以请plenilune168给一些实例代码吗?
希望plenilune168不会认为我是得寸进尺,呵呵
publicnews@163.com
深深感谢!
 
publicnews 已经发到你的邮箱了,主要思想就是重用代码,希望能够对你有所帮助

另外发给你的例子中因为用到很多第三方组件或者是自定义的组件,你应该不能用Delphi正常打开,仅能作为参考代码。
 
虽然plenilune168描写得好象很不错,虽然我没参加过什么大项目,但我也觉得不太同意。

虽然封装了DataModule的变化,但对界面的支持不足。我的意见类似于MVC,也就是在Form和DataModule之间添加 Control类。

原理很简单,说起来也很容易明白。就是类似:
FControl1 := TDFControl.Create(Form1, DataModule1) 的形式。

这样,Form1 和 DataModule1 里就不需要有任何相连的代码。

也就是说,如果你不要 Form1 的界面,改用 Form2的,如果内部 显示控件的名字是一样的话, 你只需要修改 FControl1 := TDFControl.Create(Form2, DataModule1)这一句就搞定了。
 
to plenilune168:
你显然是个在软件开发过程中动了脑筋的日,自己总结了经验,并且在实践中加以运用,我也相信你的这些实践是有正面意义和效果的。对此,我向你表示敬意。
然而,我必须指出,你上面提出的方法,其本质并不是OO的。从你的帖子来看,你不过是提供了一系列的全局方法库而已,这和OO扯不上任何关系。(当然,提高一个有效的方法库是能够提高生产效率的,但这和楼主的要求偏离了,同时也可能误导其他新学)
另外,对于楼主关于继承的疑惑,我想提醒你,“继承”这一特性在OO方法论里面是争论最多的,许多OO专家是不提倡继承的。请你记住:使用了继承特性,不表明增加了你的程序的OO特性;反之亦然。
 
就一般的软件项目而言,比如一个图书馆的借还书系统,如果希望用OO的方法来实现,那么:
第一阶段是做OOA,也就是面向对象的分析,这里的目标是分析业务,并重组业务模型,这个模型应该是OO的,也就是说这个被建立起来的模型是通过模型内的对象以及对象关系来描述的。相对面向过程的分析(OPA),OPA的模型是通过一件件事情的发生/展过程来描述的,例如流程图就是典型的OPA描述工具。
从OOA得到的模型中,应该是可以清楚识别出各个业务对象的。对于图书馆来说,应该可以分析出3个/类的对象:书、阅读者、图书管理员。存在的关系是:阅读者检索书的信息、阅读者向管理员借/还书、管理员检索书的信息。
 
第二阶段是做OOD,也就是面向对象的设计,这里的目标是将前一阶段得到的业务模型转化为计算机模型。OO的优势在这里就体现出来了,因为只要从业务模型里的对象里面抽象出我们感兴趣的属性,就基本完成了这部分工作(当然,这里面还是有一些需要高级技巧的东西,否则系统架构师也太容易当了)。如果是面向过程的设计(OPD),这阶段就复杂得多,因为OOD几乎是一一对应的映射,而OPD就麻烦很多了。
对于图书馆来说,应该将书与阅读者设计成实体对象,而管理员是边界对象。(以上是按照UML的分类,在J2EE里面就对应为两个实体BEAN和一个会话BEAN,如果是按照MVC模型,则书和阅读者是M,管理员是C)。此外,设计中还应该有书的集合的管理者和阅读者的集合的管理者(在J2EE中集合的管理者是通过中间件的EJB容器实现的;在DELPHI中,就得自己手工写代码来实现了)。
 
到了第三阶段,才到楼主所说的OOP(其实,如果没有OOA与OOD,想进行OOP是不大可能的。这也是为什么大部分人在OOP前感到困惑的原因)。
这里要对前阶段的设计进行实现。如果前期工作到位,OOP其实很简单。如果用DELPHI,对图书馆的例子,就应该先设计个“书”的类(我这里是简化假设每种书只有一本,ISBN是ID):
TBook = class(TObject)
private
FName: string;
FAuthor: string;
FIsbn: string;
FStatus: BookStatus;
public
.............
end;
注意,在这个TBook类内部应该实现其和数据库的影射。所有与书打交道的对象够不需要关心它与数据库是怎么联系的,只要找到并使用它就可以了。此外,在TBook里面是不应该实现任何与借和还有关系的方法的,因为书是自己无法实现借和还的,它的借/还是由其管理者——管理员来实现的,管理者操作书,并改变其STATUS。

还需要实现书的集合管理者,也就是书的容器。它负责书的生命周期的管理和检索。
TBookPool = class(TObject)
private
FBookList : TObjectList;
.................
public
........................
end;

阅读者和阅读者的集合管理者与前面的书是类似的。

然后就是管理员了。它实现借方法与还方法:
TOperator = class(TObject)
public
Boolean lend(pBook: TBook
pReader: TReader);
Bookean return(pBook: TBook);
end;
 
先看看plenilune168的代码
对于jeffrey_s的FControl1 := TDFControl.Create(Form1, DataModule1)没有明白是什么意思

再请教"沙隆巴斯的主人&quot
有关下面这一句:
--------在这个TBook类内部应该实现其和数据库的影射
这也就是我在烦恼的问题,我可以前对象抽离出来,但对象如何实现数据集的读写我是茫茫然
请大侠指点
我目前只是将所有的东西当成一个数据集做数据库的读写,用对象我就不知道如何读写了...
 
to jeffrey_s
其实对于你说的界面支持已经在公共的窗体类中定义了

type
TfgForm=class(TForm)
……
Flag_Funs:TfgGlobalFunction
//全局函数对象(公共函数)
Flag_Vals:TfgGlobalValue
//全局窗体调用对象(包括每个模块的调用函数)
Flag_Form_Main:TForm
//系统主窗体
Flag_Modal_Data:TDataModule
//数据模块
end;

也就是说完全可以在任何一个窗体内调用所有其他窗体,包括数据模块
 
to publicnews:
在DELPHI中,你必须手工实现对象与数据库的映射,一般是在对象的与生命周期有关的方法中。例如:在TBook的Create方法中,应该是对应于向数据库insert;destroy方法应该是delete。但要注意的是,这里有两个不同的生命周期:一个是对象在内存堆里的生命周期,另外一个是对象在业务系统中的周期。我上面指的是第二个。
以上的做法,很类似于J2EE里面的BMP模式,都是对象自己管理持久化。但J2EE可以提供更好的框架支持。其实,J2EE提供了更好的CMP模式,所有的与数据库打交道的工作都交由J2EE容器去管理了,程序员几乎可以不用一句SQL,这在DELPHI中就望尘莫及了。也就是由于这方面的原因,用DELPHI用到一定程度,自然而然就转向J2EE或。NET了。
 
to 沙隆巴斯的主人:
图书管理系统进行的如何了?
 
to 沙隆巴斯的主人:

怎樣了﹐發個來看看

john163mail@163.com
 

Similar threads

回复
0
查看
676
不得闲
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
892
DelphiTeacher的专栏
D
顶部