讨论并散分:如何处理组织机构与员工的关系?(300分)

  • 主题发起人 主题发起人 冰冷的雨
  • 开始时间 开始时间

冰冷的雨

Unregistered / Unconfirmed
GUEST, unregistred user!
假设每个员工只属于某一个部门,则部门与员工是1..n的关系,由此设计部门类TOrgan
和员工类TPersonnel如下:
TOrgan = class
private
FID: integer;
FName: string;
FParent: TOrgan

FEmployee: TPersonnelList

...
public
...
function GetEmployes: TPersonnelList

end;

TPersonnel = class
private
FID: integer;
FName: string;
FParent: TOrgan

...
public
...
end;

TPersonnelList = class
private
FItem[Index: Integer]: Personnel;
FCount: Integer;
...
public
...
function GetPersonnel(Index: integer): TPersonnel;
end;
个人感觉这种方案有几个缺点:
1、部门类TOrgan和员工类TPersonnel耦合太强;
2、三个类之间形成了循环引用,不符合OO的封装原则;
3、当组织机构比较复杂或者员工较多时,会占用大量的内存。
大家一般是怎么处理的?或者有什么好的想法请一起讨论。
 
不适合用OO做这样复杂的处理,比如你要是想计算salary,那就可以写个服务函数
function Salary(ADataSet_Emps: TADODataSet): double;
就可以了,而参数,是你用SQL查询出来的若干员工,只是这样对数据库结构又有耦合了,总体来看,算是一种比较可行的办法,软件以“经济”为本
耦合不可避免,较好的设计只是取一个比较折衷的结构
假设你把ER图全部使用OO的Class来表达,ER图也是经常会变化的,那么到时候你还是得修改Class的定义,这样也有耦合。
 
人事考勤里用吗?
 
TO icc: 您说的很对,但这种方法不适合对每个部门/员工进行控制。
考虑一个机关的办公自动化系统:
每个员工都是系统的用户,系统需要对每个员工的权限、公文传递关系等进行控制;
员工需要在系统中处理自己的各种事务。
如果仅仅用SQL查询对员工进行管理,系统将很难组织。

TO 网中戏:呵呵,我在做一个局域网行为管理系统。当然,人事考勤、办公自动化、
工资,还有我们单位的一些业务软件,都涉及到这个问题。不过,人事考勤等系统
用icc的方法做可能更合适,我只是想找几种比较通用的结构,或者用流行的说法,
相当于几种设计模式吧。
 
想了一天,改为这种方式,大家看看怎么样:

增加一个TPersonDisp记录,原来的TPersonnelList改为TPersonDispList,
在TOrgan中只引用TPersonDispList,可以用于显示,需要对某一员工进行处理
的时候再创建一个TPersonnel对象,用SQL读入该员工的数据
(TPersonDispList.GetAnPerson),事务完成后释放该对象。这是基于同一时间内可能
有多个员工的信息需要显示,但只能对一个员工或者只能有一个员工进行操作。
TPersonDisp = record
ID: integer;
DispString: string

end;

TPersonDispList = class
private
FItem[Index: Integer]: TPersonDisp;
FCount: Integer;
FParent: TOrgan;
...
public
...
function GetPerson(ID: integer): TPersonnel;//创建一个TPersonnel对象
//用SQL获取指定ID的员工数据
end;


TOrgan = class
private
FID: integer;
FName: string;
FParent: TOrgan

FEmployee: TPersonDispList
//原来是FEmployee: TPersonnelList;
... //在创建TOrgan对象时指定该对象为它的Parent
public
...
function GetEmployes: TPersonDispList;
end;

TPersonnel = class
private
FID: integer;
FName: string;
FParent: integer
//所属部门的ID
...
public
...
end;
 
我觉得你的解藕意义不是很大, 如果你要解藕,可以采用接口的方式, 这样肯定依赖性就降低了。
但是设计一定要到够用为止, 不要考虑太远,这样你永远做不完设计。 只要你的代码适合当前的需求就可以。 可以灵活扩展就是好设计了。
 
TO duhai_lee: 谢谢,能举个用接口解耦的例子吗?
 
我觉得不了解整体的需求很难说应该怎样设计,但基本的感觉是应该把员工类作为主要类来设计,或者将业务变化较大的作成接口方式。例如:
IPersonnel=INTERFACE
Function a()
..
 
关于需求:
一、组织机构
市局
|--县区局1
| |--科室1
| |--科室2
| |--...
| |--科室n
| | |--所A
| | |--所B
| |--所1
| |--所2
| |--...
| |--所n
|--县区局2(类似于县区局1)
| ...
|--县区局n(类似于县区局1)
二、以上组织机构的每一级下面都有若干人员和设备(电脑、网络设备),
系统要:
1、对各单位的资产进行管理,包括设备、耗材、配件的采购、保管和发放;
2、对每个人员的系统操作权限进行管理;
3、对每个人员的设备使用权限进行管理;
4、对每个人员在每台设备上所连接网络(内网和因特网)进行管理;
5、对每个人员在每台设备上安装的软件进行管理;
6、权限采用用户-角色-组模式控制

关于接口,用法是知道(参考smokingroom的《OOP在三层系统中的应用》
http://www.delphibbs.com/keylife/iblog_show.asp?xid=386,
刘义《DELPHI面向对象编程》),只是不知道如何设计比较合理
 
谈谈我的看法 :)
====================================
个人感觉这种方案有几个缺点:
1、部门类TOrgan和员工类TPersonnel耦合太强;
2、三个类之间形成了循环引用,不符合OO的封装原则;
3、当组织机构比较复杂或者员工较多时,会占用大量的内存。
大家一般是怎么处理的?或者有什么好的想法请一起讨论。
-------------------------------------
1. 同层的业务类之间,这种程度的藕合不算强了。问题在于,在现在这种设计下,你以后应该不会有要完全拆开TOrgan跟TPersonnel的需求。最可能的变动是,你需要通过继承扩展TOrgan或者TPersonnel。这种情况下,你现在的接口问题不大。 另外,你的TOrgan与TPersonnel类其实有很多相似点,例如都有ID, Name, Parent。可以根据《Analysis Patterns》里的建议,做个TAccountable的基类,把公共属性提取出来,TOrgan与TPersonnel都从TAccountable里继承。具体结构可以参阅《Analysis Pattern》

2. 这不算循环引用,双向连接而已。封装是指通过接口隐藏实现细节以及通过接口限制客户对象访问内部逻辑,并不是反对对象间互相连接。

3. 使用“延迟读入”或“代理空对象”模式。可以参考《企业应用架构模式》中关于 延迟读入 的章节。

==================================
想了一天,改为这种方式,大家看看怎么样:
--------------------------
你这种做法就是“代理空对象”了。实现细节还有些要注意的地方,但我习惯用“延迟读入”,“代理空对象”的做法不太熟悉,建议去找找有关资料。
==================================
《OOP在三层系统中的应用》那篇笔记中所说的接口主要是指COM+的远程访问接口,跟你问题中的业务类精细接口是有点差别的。
 
查了下,《Analysis Patterns》中文名叫《分析模式:可复用的对象模型》。算是一本关于写业务类的好书,值得一看
 
谢谢大家的高见,特别是kidneyball,有空还请指导一下“延迟读入”,还有远程访问
接口和业务类精细接口的具体区别(我只知道参数传递和引用计数方面的区别)。
《Analysis Patterns》我看过,不过英文不太好,只能懂点大概,好像没出中文版的。

TO duhai_lee:请到另一个帖接分。
 
多人接受答案
 
后退
顶部