5

我正在审查一些代码(Java)并根据业务逻辑流程图进行更改。当前的代码依赖于大量的 if 语句——我想尝试摆脱这种情况。我一直在阅读有关多态性的内容,并试图围绕如何将其应用于我的情况而思考。我可以使它适用于单个条件级别,但很难将其进一步扩展到多个条件级别。代码将在运行时执行,此“逻辑”方法将传递上一步中的变量。

人为的例子:我们有 2 个动物园,“动物园 A”和“动物园 B”,以及“家”。这些中的每一个都是一个“地方”。在每个动物园中,我们有 4 个“位置”、“北”、“南”、“东”和“西”。“家”只有一个位置。我们想根据几个变量为一个人分配一个“目的地”,让他们知道他们应该去哪里。这些变量是:“地点”,与我们的地点(动物园 A、动物园 B、家)相关。'方向',与我们的位置相关,(N,S,E,W)。流程图:

                |----- | 'HOME'
                |Place?| ----- >  *destination = 'home'*
                |----- |
     Zoo A          |                               Zoo B
    |---------------|----------------------------------------|
|----------|                                        |----------| 
|Direction?|                                        |Direction?| 
|----------|                                        |----------|
    |    North                                          |    North
    ----------- *destination = 'Zoo A North'            ----------- *destination = 'Zoo B North'
    |    East                                           |    East
    ----------- *destination = 'Zoo A East'             ----------- *destination = 'Zoo B East'
    |    South                                          |    South
    ----------- *destination = 'Zoo A South'            ----------- *destination = 'Zoo B South'
    |    West                                           |    West
    ----------- *destination = 'Zoo A West'             ----------- *destination = 'Zoo B West'

因此,如果人 X 有一个动物园 A 的地点和一个南方向,那么他们应该有一个“动物园 A 南”的目的地

我的代码目前使用 If 语句非常难看:

if(Place = 'HOME')
    destination = 'HOME'
if(Place = 'Zoo A')
    if(Direction = North)
        destination = 'Zoo A North')
    if(Direct = East)
        destination = 'Zoo A East')
    ...
if(Place = 'Zoo B')
    if(Direction = North)
        destination = 'Zoo B North')
    if(Direct = East)
        destination = 'Zoo B East')
    ...

我可以把它变成嵌套开关,变量为 ENUM。但我试图避免 if - else / switch 依赖,因为我有一个坏习惯,陷入其中。我尝试使用 Factory Design 来生成 Place 类,然后在每个位置和目的地上使用多态,但它开始在我的脑海中变得过于复杂。是否值得远离 if/switches?我只是想过度设计它吗?

关于如何处理这样的逻辑流程有什么建议吗?谢谢

4

8 回答 8

3

这可以这样建模:

  1. 使用根类Place,带有方法calculateDestination(Person)。Place 可以包含其中的其他地方。
  2. 为and创建Place子类(当然,因为这些是实际的地方)。ZooZooQuadrant
  3. Person对象具有currentPlacecurrentDirection

现在您将实例化这些类的对象来表示您的情况:

zooA = new Zoo("ZooA");
zooA.addChild(new ZooQuadrant(Direction.SOUTH));
... so on for every quadrant ...
... same for zooB ...
home = new Place("Home");
world = new Place("World");
world.addChild(home);
world.addChild(zooA);
world.addChild(zooB);

当你想到达目的地时,你会打电话world.calculateDestination(myPerson)

calculateDestination(Person)是多态方法。继承层次结构中的每个级别都将根据该类的特定语义覆盖它。

  1. Place将有一个通用实现来测试Person实例当前是否在该节点(通过测试Person的值currentPlace),如果不是,它将调用它calculateDestination的每个子节点并返回它。
  2. Zoos 将需要检查是否currentPlace == this,如果是,则调用calculateDestination它的每个象限并将任何积极的结果与其自己的结果相结合以返回this.name + quadrantResult
  3. 每个ZooQuadrant只需要检查 是否currentDirection等同于自己的方向,并相应地返回一个值。

注意:这只是为了说明多态是如何工作的,可能会有更好的实现。此外,这里我们同时使用多态性和递归,两者是独立的。


编辑:

至于是否需要增加复杂性,这取决于!在这里,我们使用一个非常小的对象图的简单示例。一旦您有数十个动物园,必须在这些动物园中添加更多象限,或者需要做出额外级别的决策(例如,如果每个象限都有子象限),嵌套的 if-else-if 方法(程序)变得非常毛茸茸的很快,而面向对象的方法仍然可以维护和理解。

像所有事情一样,如果您预见到决策会变得如此复杂,请使用 OO 方法。否则,每次都保持简单胜过美观:使用正确的工具解决正确的问题。

于 2013-01-10T01:36:30.150 回答
0

一种方法是您可以使用 getNorthDestination()、getEastDestination() 等方法创建父抽象类/接口“Place”。

然后创建一个名为“ZooA”和“ZooB”的“Place”子类/实现,并覆盖/实现 getXXXDestination() 方法以返回相应的位置

于 2013-01-10T00:58:27.357 回答
0

从这里我看到至少三个类是 Place、Direction 和 Destination。

Place 将有一个 name 属性和一个 getName() 方法,名称被设置为 Zoo A、Zoo B、Home。

如果 Home 和 Zoo 具有不同的行为,您将创建 Place 的子类。在这种情况下,您可以这样做,因为 Home 没有方向,但 Zoo 有。

方向可以是一个包含北、东、西、南的枚举(它只是一种特殊类型的类)。

Destination 将有两个属性,即 Place 和 Direction。它还有一个方法 getDestination()

public String getDestination(){
    if (this.direction == null){
        result = this.place.getName();
    } else {
        result = this.place.getName() + " " + this.direction.getName();
    }
    return result;
}
于 2013-01-10T01:06:38.743 回答
0

跟着格里坦的回答走。对于每条信息,您都应该问自己:“我真的需要为此开设课程吗?”。很多时候,答案是否定的。简单的字符串/数值变量就足够了。现在,您希望将这些变量与 getter/setter 方法结合起来,因为这是 java 所强调的,而不是直接引用公共变量(例如 C++)。引用简单的方法比例如测试要容易得多。

于 2013-01-10T01:08:49.203 回答
0

你可以在其中创建一个包含 Zoo A 和 Zoo B 的新方法……你可以像 directionForZoo() 一样调用它,如果尝试使用 while 循环

于 2013-01-10T01:17:31.800 回答
0

如果您不想过度设计它,以下解决方法将是摆脱 if/else 的简单解决方案。但这不是一种优雅的方法。

您可以有一个地图,其中键是(地点+方向),值是相应的目的地。仅当 Place 和 Direction 值在您的程序中现在更像是静态的并且不太可能发生太大变化时,这才可以。

例如:将您的地点和相应的目的地存储在地图中

Map<String, String> destMap = new HashMap<String, String>();
destMap.put("HOME","HOME");
destMap.put("Zoo A+North","Zoo A North");
destMap.put("Zoo A+East","Zoo A East");
destMap.put("Zoo B+North","Zoo B North");

根据 Place 和 Direction 检索目的地:

destMap.get(Place + "+" + Direction);
于 2013-01-10T05:27:12.313 回答
0

您的示例的一种可能解决方案是创建一个(可能是抽象的)Location类。这可以包含您的目的地的数据结构。这种数据结构的一种可能性是 a Map<Direction, Location>) 其中Direction是一个枚举,它可以用作映射到一个Location对象的键,该对象是该方向的目的地。您可以创建子类Location以创建HomeZoo等类,也可以提供一个name区分不同Locations 的字段。或者您可以将这两者结合起来。

请注意,这是一个半生不熟的设计,可能会也可能不会满足您的需求。良好的 OO 设计需要经验和详细了解您要解决的问题的确切要求。我对前者有些了解,但对后者了解甚少。

于 2013-01-10T17:32:44.450 回答
0

我尝试了一些建议的答案的变体。

我最终使用了一个嵌套的 switch case 块。不是最理想的,也是我想避免的,但出于我的目的,它更易于维护(它不会改变或扩展)。

我将@Ezequiel Muns 方法标记为正确,因为我的版本运行良好 - 它只是不是问题所需要的。

感谢所有的帮助。

于 2013-01-16T08:38:42.663 回答