一个OOAD的设计问题(转帖+理解)

原文地址:http://www.cnblogs.com/bluedoctor/archive/2011/06/01/2067177.html#pagedcomment

   在RPG游戏中,人物携带物品在地图中走动,不同的物品具有不同的功能,如果就这么简单,那对物品的使用,就可以成为物品的一个方法,使用物品就调用这个方法好了。

    很要命,不同的人物使用同一件物品的时候,效果也不一样。

    这时候还要把这个方法放到物品对象中吗?

    也许还可以,OO分析会开始非人类的胡言乱语:如果在方法调用中,加上user参数,那么物品知道是谁在使用它,于是就可以根据使用者的不同来进行不同的处理了。

    卖锅的,物品居然活了,它成了一个精灵,知道谁在使用它。

    好吧,这样是可以了。但问题是,做为一件物品,它为了根据使用者的不同来进行不同的处理,那么它就得知道使用者的类型,耦合就产生了,即使你又抽象出某种公共的接口,耦合依然存在,但处理上会稍微舒服一些。

    有人试图改变这种耦合,把使用物品的方法加到了人物对象上,只不过是顾头不顾腚的做法,按下葫芦浮起瓢。这里的耦合不见了,会在另外一个地方冒出来,只不过,有经验的设计者会预先知道这一点并权衡不同方式的利弊,对于性质不同的系统,采用不同的处理方式。

    如果再加上一种,那就是场景,比如地上打和地下使用不一样,在庄稼地和宫殿里使用也不一样,那又该如何?

    请园子里面的大牛,告诉我这个问题该如何OOAD?

 

下面是我和作者的一些评论:

 

#22楼2011-06-02 13:57zylcf818      

head first设计模式开头的那个例子(关于鸭子及其行为的)和你这个有相似性。先看一下那个例子,再看我下面的内容会更好理解。
我的一些初步看法是user和物品都设计成接口,这样就把具体物品和具体user间的耦合解耦了。
user本身聚合有很多物品,在使用的时候只调用物品的use方法就行了,这里有几点说明:
1 在调用的时候,user和环境对象(也就是各种影响动作执行的因素数据)作为参数传入use方法中,这里罗嗦2句:除非特殊原因,一定要用参数传入,不要让物品从其他途径获得,原因大家应该明白;
2 具体的物品对象的use方法内部如何处理,看你了,逻辑简单用if else判断各种影响因素后执行那个动作,如果逻辑复杂,还是要在分析,这里又要罗嗦2句,对于不同情况,千万不要用继承的方式去对应各种case,这样会造成类爆炸,应该使用对象组合将动作再分解为小对象后组合到具体的物品对象里。
3 user通过系统获得物品,user可以有一个receive接口,其参数是物品接口,系统通过user的receive方法给user增加一个物品,user不用关心该物品的具体类型
举个例子:
角色和武器之间的关系,武器的使用受到角色(如精灵,矮人等),环境(空中,地上,沼泽)和角色等级等因素的影响。用2个接口表示角色和武器:IRole and IWeapon,
interface for IRole:
...
void add(IStuff aStuff)// IWeapon is subclass IStuff,个人觉得不要用addWeapon接口,这样的接口设计很僵硬

interface for IWeapon:
...
void attack(IRole owner, IEnviroment aen, IRole aenemy)// use应该是IStuff的接口,attack是IWeapon的接口;

 

#24楼[楼主]2011-06-02 18:39深蓝医生      
@zylcf818
2 具体的物品对象的use方法内部如何处理,看你了,逻辑简单用if else判断各种影响因素后执行那个动作,如果逻辑复杂,还是要在分析,这里又要罗嗦2句,对于不同情况,千万不要用继承的方式去对应各种case,这样会造成类爆炸,应该使用对象组合将动作再分解为小对象后组合到具体的物品对象里。
---------------
看来这个物品对象还是一个“精灵”啊,它要根据传进来的user接口具有的属性,如角色,等级等,在结合环境因素,来最终决定自己该如何use.
也许你的方案可行,但会有一堆的if else,或者一堆对象的组合,怎么做我都觉得,方案具体实施还是太复杂。

#25楼2011-06-04 15:00zylcf818      
@深蓝医生
怎么做我都觉得,方案具体实施还是太复杂。
代码的逻辑必然要反映业务的逻辑,如果你的业务逻辑简单,代码逻辑自然也简单,这是规律。
看来这个物品对象还是一个“精灵”啊
在做OOAD时,考虑的是对象的职责以及怎样隔离变化,UI上的表现和底层的对象不可能都有直接必然的映射和关联。

没有方案一开始就是复杂的,最开始的方案都是简单的,复杂是由于各种需求和其他因素逐步进化造成的,你也可以看看另一个例子:《重构-改善既有代码的设计》里面开头用的一个简单例子,关于电影租赁系统的,演示了随着需求的变化,而使系统逐渐复杂起来的过程。

#26楼[楼主]2011-06-04 16:59深蓝医生      
@zylcf818
谢谢兄弟的回复,看来复杂性无法避免,我想的是,这类复杂的问题,能否找到OOAD之外的方法。实际上本文的问题不是我提出来的,而是另外一个朋友在博客中的讨论,他提出可以使用Prolog的Horn字句来解决这类问题,也就是“陈诉式”的编程方式,采用语言内置的推理机来解决问题。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章