论坛首页 Java版 企业应用

OO design trap

浏览 35158 次
锁定老贴子 主题:OO design trap
该帖已经被评为精华帖
作者 正文
最后更新时间:2005-12-23
需求如下:
有这样一家超市,对顾客实行会员制,会员目前分为两个等级:金卡及银卡。
每次会员购物时,都会根据会员等级提供不同的折扣优惠和返点。

设计方案有三个:
1. 过程设计,用作对比
2. 过程式的OO设计,简单来说就是将过程设计中的函数封装到类里面
3. 标准的OO设计,封装、继承、多态、设计模式,能用的都用上

问题:
如果是你,你会采用哪种OO设计,或者有更好的设计?


过程式设计:
[code:1]
// client:

string id = input_id;

string type = GetMemberTypeByID();

int discount = GetDiscountByType(type);
int point = GetReturnPoint(type);


// service:

string GetMemberTypeByID(string id)
{
string type;

// get type by id
...

return type;
}

int GetDiscount(string type)
{
switch(type)
{
case "金卡":
return 10;

case "银卡"
return 5;
}

return 0;
}

int GetReturnPoint(string type)
{
switch(type)
{
case "金卡":
return 1.5;

case "银卡"
return 1;
}

return 0;
}
[/code:1]

OO设计1(仅使用封装特性)

[code:1]
// client:

string id = input_id;

Member member = new Member(id);

int discount = member.GetDiscount();
int point = member.GetReturnPoint();

// service:

class Member
{
string type;

public Member(string id)
{
type = GetMemberTypeByID(id);
}

protected string GetMemberTypeByID(id)
{
string type;

// get type by id
...


return type;
}

public int GetDiscount()
{
switch(type)
{
case "金卡":
return 10;

case "银卡"
return 5;
}

return 0;
}

public int GetReturnPoint()
{
switch(type)
{
case "金卡":
return 1.5;

case "银卡"
return 1;
}

return 0;
}
}
[/code:1]

OO设计2(使用封装、继承及多态特性)
[code:1]
// client:

string id = input_id;

Member member = Members.GetMemberByID(id);

int discount = member.GetDiscount();
int point = member.GetReturnPoint();

// service

class Members
{
static public Member GetMemberByID(string id)
{
string type = GetMemberTypeByID(id);

switch(type)
{
case "金卡":
return new GoldenMember();

case "银卡"
return new SilverMember();
}

return null;
}

static protected string GetMemberTypeByID(id)
{
string type;

// get type by id
...


return type;
}
}

class Member
{
protected Member()
{
}

virtual public GetDiscount()
{
return 0;
}

virtual public GetReturnPoint()
{
return 0;
}
}

class GoldenMember
{
override public GetDiscount()
{
return 10;
}

override public GetReturnPoint()
{
return 1.5;
}
}

class SilverMember
{
override public GetDiscount()
{
return 5;
}

override public GetReturnPoint()
{
return 1;
}
}
[/code:1]
   
最后更新时间:2005-12-23
最后一个的 switch 最少,就选最后一个。

每次添加一个新的类型,所有hard coded switch的地方都需要修改。修改的地方,当然越少越好。最好就是只添加新类,不改动任何旧类代码。
   
0 请登录后投票
最后更新时间:2006-07-23
居然我是第一个投票的!呵!
我选最后一种.
这个例子和"马同学"在TDD里举的那个币制问题类似.
   
0 请登录后投票
最后更新时间:2005-12-23
第三种其实和前面的半斤八两........
   
0 请登录后投票
最后更新时间:2005-12-23
都不选行不,看起来不爽
看见switch就头疼
   
0 请登录后投票
最后更新时间:2005-12-23
T1 写道

设计取决于数据源的形态,如果换一种数据源形态,第三种方式可能就是最差的。比如我把金牌,银牌的折扣放入一个Pair (就是Hastable)。那么第三种方式就是最差的。
   
0 请登录后投票
最后更新时间:2005-12-23
buaawhl 写道
T1 写道

设计取决于数据源的形态,如果换一种数据源形态,第三种方式可能就是最差的。比如我把金牌,银牌的折扣放入一个Pair (就是Hastable)。那么第三种方式就是最差的。

还应该包括是否有足够的行为使得抽取成单独的类成为充分的重构可能。

如果仅仅从获取折扣点这个需求来说,还不能成为要单独设计不同的类的充分条件。

如果随随便便就用单独的类来作,很容易造成过度设计,过度设计的后果就是使得类庞多而复杂。
然而,只要要多几个行为特性发生在这不同的类型上面,那么即使不考虑数据源的设计,类的抽取也是必要的。
   
0 请登录后投票
最后更新时间:2005-12-24
是不是用不同的类还是switch其实以目前的需求来看都半斤八两啊。

只要客户接口定下来了,后面怎么实现Member那还不是随时可以重构的?

不喜欢swtich,也可以登记到一个hashtable里面,但这都是细枝末节了亚。有啥可说的?
   
0 请登录后投票
最后更新时间:2005-12-24
OO 多态的作用就是用来消除 hard coded logic branch (if, else, switch)。

如果使用了hashtable, 这几种做法都消除了 hard coded logic branch ,那OO多态的优势,自然就不存在了。那么根本就不需要使用 OO多态。

如果题目的本意,就是表面给出的这么简单基础,使用hashtable就能很好的解决,我估计大多数具有基础基本功的人都知道如何解决,那么这个帖子还有什么意义?

既然楼主给出了这个例子。我们自然假设这是一个足够复杂需求的简单示意。hard coded logic branch 无法简单的使用hashtable来消除。在这样的假设的基础上,才具有讨论的意义。
   
0 请登录后投票
最后更新时间:2005-12-24
很巧,刚刚做过的一个项目也是有用户积分和等级制度

我把所有的point-level pair以及level-rebate pair都放到xml里面

没有大的业务扩展的话 只需要定义新的或者编辑现有xml中的pair即可 而不用添加新的class或者method

所以俺选2
   
0 请登录后投票
论坛首页 Java版 企业应用

跳转论坛:
JavaEye推荐