锁定老帖子 主题:OO design trap
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2005-12-24
buaawhl 写道 OO 多态的作用就是用来消除 hard coded logic branch (if, else, switch)。
如果使用了hashtable, 这几种做法都消除了 hard coded logic branch ,那OO多态的优势,自然就不存在了。那么根本就不需要使用 OO多态。 如果题目的本意,就是表面给出的这么简单基础,使用hashtable就能很好的解决,我估计大多数具有基础基本功的人都知道如何解决,那么这个帖子还有什么意义? 既然楼主给出了这个例子。我们自然假设这是一个足够复杂需求的简单示意。hard coded logic branch 无法简单的使用hashtable来消除。在这样的假设的基础上,才具有讨论的意义。 类的抽取足够必要,但是多态的抽取就看具体的情况了。 |
|
返回顶楼 | |
发表时间:2005-12-26
我的习惯是,多用组合、接口,慎用继承,必要的话使用服务性质的类
-----Server------ //感觉通过Member去获取折扣有点别扭,提到Payment里面了 class Memeber { protected string m_type = ""; public string Type { get { if(m_type == ""); { GetType();; } return m_type; } } public string GetType(); { // from db or somewhere else } } class Payment { //Payment未必是一个需要实例化的类,提供一个类似服务的静态接口 public static decimal GetDiscount(Memeber member); { Discount discount = null; switch(member.Type); { case "金卡": discount = new GoldenDiscount();; case "银卡" discount = new SilverDiscount();; } return discount.GetDiscount();; } } //如果Discount的计算规则够简单的话,不需要这个继承树 class Discount { virtual protected decimal GetDiscount(); { return 0; } //如果计算Discount的时候需要member的某些信息的话 virtual protected decimal GetDiscount(Member member); { return 0; } } class GoldenDiscount :Discount { //overrdie 。。。。 } class SilverDiscount : Discount { //overrdie 。。。。 } -----Client string id = input_id; Member member = new Member(id);; int discount = Payment.GetDiscont(member);; |
|
返回顶楼 | |
发表时间:2005-12-26
如果用接口,修改的地方就是具体实现,那不是得修改更多?
|
|
返回顶楼 | |
发表时间:2005-12-26
如果用C++, 我会用你的第2种设计.
如果用java, 第二种设计可以通过反射机制, 或者干脆用spring, 把type决策的if else也去掉 |
|
返回顶楼 | |
发表时间:2005-12-26
buaawhl 写道 最后一个的 switch 最少,就选最后一个。
每次添加一个新的类型,所有hard coded switch的地方都需要修改。修改的地方,当然越少越好。最好就是只添加新类,不改动任何旧类代码。 OO设计2如果用C++做必须修改type decider. 但是如果用java可以做到只修改配置文件不重新编译 这样的系统我碰到的大多是用C++做的, 一般必须修改一个类. OO设计2对C++来说是一个不错的设计 |
|
返回顶楼 | |
发表时间:2005-12-26
interface DiscountStrategy { double getDiscount();; int getReturnPoint();; } class GoldenDiscount implements DiscountStrategy { // 实现 } class SilverDiscount implements DiscountStrategy { // 实现 } // 普通会员 class Member { DiscountStrategy strategy; Member(DiscountStrategy strategy); { this.strategy = strategy; } double getDiscount(); { return strategy.getDiscount();; } int getReturnPoint(); { return strategy.getReturnPoint();; } } // 女性会员 class FemaleMember extends Member { DiscountStrategy strategy; Member(DiscountStrategy strategy); { super(strategy);; } double getDiscount(); { double discount = strategy.getDiscount();; // 计算附加优惠 return discount ; } } 某天boss心血来潮,给大于60岁的男人某种特殊优惠,那我就再给他加一个特殊的Member子类。某天boss心血来潮,搞出一大堆的乱七八糟的组合,那我就给他重构到Decorator模式。 |
|
返回顶楼 | |
发表时间:2005-12-26
T1 写道 俺们来CO一把 附件里面是T1的一个Discount CO实现。 |
|
返回顶楼 | |
发表时间:2005-12-26
如果增加白金卡, 钻石卡, 铜卡, 铁卡, 铝卡
你还是要修改你的fill_type_stream , 如果用C++你的这种设计非常认同, 如果用java应该改进一把, 总归修改代码有点bed smell(虽然大多数情况下不可避免) |
|
返回顶楼 | |
发表时间:2005-12-26
zengjin8310 写道 如果增加白金卡, 钻石卡, 铜卡, 铁卡, 铝卡
你还是要修改你的fill_type_stream , 如果用C++你的这种设计非常认同, 如果用java应该改进一把, 总归修改代码有点bed smell(虽然大多数情况下不可避免) T1 写道 为什么非要修改,添加不行么? |
|
返回顶楼 | |
发表时间:2005-12-26
partech 写道 呵呵,我看问题不是什么是最好OO设计的问题。而是如何划分职责的问题。 正如 evanyuan指出:“感觉通过Member去获取折扣有点别扭”,你在这里 职责划分有问题,就导致了你后面子类爆炸的结果。 注意:你要解决的问题是根据member的属性,提供复杂折扣和返点的计算。 也就是说变化的是这种依赖member的计算,而不是member本身有了什么变化。所以不要再瞎折腾member了。 就只以折扣为例,简单的实现如下: public class Payment{ public Decimal pay(Member member, Order order);{ Decimal amount; //计算实际总额 ...... return amount * getDiscount(member,order);; } private Decimal getDiscount(Member member, Order order);{ Decimal discount; switch(member.type); { case "金卡": discount = ...; case "银卡" : discount = ...; } switch(member.sex); { case "女": discount += ...; } } } 这里假设,折扣只同member和order的信息有关,那么将来的任何变化,都可以只从getDiscount扩展出去。 这又是一个“概念依赖”的例子,好的DomainModel,就是职责划分合理的结构,而能打开这扇门的钥匙,我认为就是“概念依赖”。 这种设计显然就是设计1的变种,只不过是将原来的Member拆成两部分,本质上依然是过程设计。OO的核心价值是封装、继承及多态,仅从封装角度来细分职责我认为是不足以体现OO价值的。 |
|
返回顶楼 | |