一个简单的设计问题,请自认为在设计方面有一定了解的朋友们进来看一看(100分)

L

liguang

Unregistered / Unconfirmed
GUEST, unregistred user!
在撰写类时,对这个类的一些假设经常会象是梦魇一样,挥之不去。
也许这话太抽象,下面具体举一个例子。
我需要撰写个服务器端使用的类,这个有这样一个特别,它会在构造的时候去检查外部的一
个标志,如果这个标志的值为TRUE那么,那么则允许调用这个类的public部分以实现特定的
的功能。如果这个标志的值为FALSE的话,那么我则应该采取一些手段使用户不能够实现只有
标志为TRUE的时候类才能够去执行的代码。
至于这里采取的手段,一般有两种,一种就是在这个类的每一个公有函数的入口处设置检查
标志(去检查这个标志是否被初始化为了TRUE),如果为TRUE的话,那么则执行具体的代码。
另一种可采取的手段,则是在构造函数当中抛出异常,以提示客户类初始化未成功(因为标
志为FALSE)。
这两种手段都对使用这个类的客户提出了一种假设。对于第一种手段来说,用户在未来每加
一个公有方法或者与公有方法有关的方法的时候,都需要在这个方法的入口处写入检查代码。
而对于第二种手段,则必须在每一个构造后对象的指针的地方都去检查这个指针是不是nil
如果这个指针是nil的话,那么则不允许用户调用这个指向所指向对象的方法。
当用户调用这个类新增的方法,来为客户程序增加新的功能的时候,它必须遵守这些假设所
提出的规则,这就象是给这个类安了一个定时炸弹一样,说不定什么时候这颗炸弹就会爆炸
(也许是当我几个月之后重新将这段代码翻出来修改,也许是一个新手加入我的项目组来对
我的代码进行修改的时候,值得注意的是,在这里文档并不是一个解决方法,好多程序员始
不善于从文档当中找到这类应该的问题)。
这类错误也是比较难以发现的,毕竟好多人发现代码可以按照他们的要求正确工作之后就停
止测试了,而忽略了可能出现的非正常环境(标志为FALSE)的情况。
当程序已经形成了一定的规模,再去调试这种问题,简直就是一件令人感觉到恐怖的事情。
小弟对此问题始终没有想到一个好的解决方案,所以这里将我自己的一些想法贴出来,还请
各位大侠们能够多多讨论,以得出一个此问题的正解。
 
可不可以这样:
一定要把标志检测放在类的构造之后吗,能否先做一类,再做一子类,检测标志如果为真
创建子类,否则创建父类。
维护时,都要修改的功能,修改父类,只修改限制功能,则修改子类
 
这样就平空多出一层类层次,而且以后维护的时候也要对此类层次进行维护。
 
因为你的要求增加了复杂性,多出一层也比较自然,维护时,只需如上所说,按需求选
其中一层维护就是了。逻辑上要清析些吧,我也只是抛块砖而已,期待好方法的出现
 
不如把那几个受限的代码放在protected的部分,
在子类中重定义为public,
然后用多态实现用标志的控制
 
TServer=class
protected
procedure proc1;virtual;
...
procedure procN;virtual;
end;

TDrivedServer=Class(TServer)
public
procedure proc1;override;
...
procedure proc2;override;
end;

TServerClass=class of TServer;
function createServerObj(Bool:Boolean):TServer;
var
SrvClass:TServerClass;
begin
if Bool then
SrvClass:=TServer
else
SrvClass:=TDivedClass;

result:=SrvClass.create;
end;
 
这个问题是我一年前提出的,现在看来可以使用null模式来解决,即为一个接口提供一个缺省为空的实现,然后建立一个工场方法(或者静态方法或者工场类),如果条件不满足的话,那么返回接口的缺省实现,而如果条件满足的话,那么就满足缺省的实现。
这个问题是我一年前提,现在看起来,我当时的想法本身就有一些问题,这类问题绝对应该先提供一个公有抽象,然后就十分好解决了。
另to majorsoft你的做法有一个问题,就是不附件ocp规范,对修改不能做到扩展。这可能会是很严重的问题。
 
to liguang,
>>"...一个问题,就是不附件ocp规范,对修改不能做到扩展。这可能会是很严重的问题"
为什么不能做到扩展,Null模式是怎么解决这个问题,你的解释,我看不太懂。:)
我还没有学习设计模式。 可不可以指教一二?
QQ:122646527. 认证:模式
 
1.自己去看设计模式方面的书籍,看过之后你会感觉到别有一番天地。
2.ocp的原则是,对扩展开放,对修改封闭。
而你的代码。
function createServerObj(Bool:Boolean):TServer;
var
SrvClass:TServerClass;
begin
if Bool then
SrvClass:=TServer
else
SrvClass:=TDivedClass;

result:=SrvClass.create;
end;
本身你这样做,就不能使代码平滑的扩展。如果你想添加第三个类的时候,那么你就必须修改和重新编译createServerObj所在的模块,而不能做到对其的扩展。此处一个比较常用的解决方法就是创建一个抽象基类,然后对抽象基类进行分别实现的方式来解决。
 
我知道你的意思,但好象抽象类也不能解决这个问题呀?
你在什么时候判断那个条件?
可不以写一下代码?
 
封装变化, 你可以加一层专门处理他,也可以内嵌标志,
肯定是因为判断很重要,所以你才要处理他, 加一层可以考虑阿
 
当出现true或false来控制某一项功能是否实现的时候,就应该考虑把它俩分开来写了。
 
工厂方法和抽象工厂模式,就是专门解决这样问题的,根据标志位,返回不同的类层次结构。
 
顶部