【问题标题】:OOP classes designOOP类设计
【发布时间】:2012-07-18 23:41:52
【问题描述】:

我的问题涉及 OOP 中的类设计。假设我们有 ItemBase,它是 Canceled、Modified 和 Additional 类的父类。我们还有 DueToBase 类 - Provider 和 Distributor 的父类。



ItemBase 可能会因 DueToBase 类而改变。

假设ItemBase 有DueToBase 类型的属性,而DueToBase 有一个叫compute() 的接口方法。计算算法与特定的 ItemBase 派生类相关。所以我们有六种不同的可能的 ItemBase-DueToBase 关系组合。

示例。

ItemBase ib = new Added();
ib.changed = new Provider(ib);
ib.changed.compute();

我的问题是如何在真正的面向对象编程中构建 ItemBase 和 DueToBase 之间的关系?我没有在计算方法中看到 swich/case 或 if 条件子句来检查 ItemBase 是哪种类型的实例。 如果 DueToBase 有另一个 XXXBase 类,其中有另一个接口方法 YYY() ,则情况会变得更糟,该方法依赖于 DueToBase 的特定实例(甚至依赖于 ItemBase)。 如何处理此类情况?这些事情有什么好的编程模式吗?也许我遵循的方向很糟糕。非常感谢您的帮助。

也许我的图表不清楚。问题在于以下... 伪代码:

doSomething(){
   if(itemBase instanceof Cancelled){
      if(dueToBase instanceof Provider)
         algorithm1();
      else if(dueToBase instanceof Company)
         algorithm2();
   }else if(itemBase instanceof Modified){
      if(dueToBase instanceof Provider)
         algorithm3();
      else if(dueToBase instanceof Company)
         algorithm4();
   }else if(itemBase instanceof Added){
      if(dueToBase instanceof Provider)
         algorithm5();
      else if(dueToBase instanceof Company)
         algorithm6();
   }
}

如果使用更深的 if 子句,情况会变得更糟。

【问题讨论】:

  • 看看依赖注入作为一个概念
  • 我知道 DI 和 IoC 是什么,但这些与我的问题无关。我在问如何处理嵌套条件以选择适当的操作
  • 你尝试过策略模式吗?看起来应该合适。
  • 为了将来参考,您应该阅读一本设计模式书籍。我推荐的一个是 Head First Design Patterns
  • @kkris1983,你是怎么解决这个问题的?

标签: java oop if-statement


【解决方案1】:

您的ItemBase 类可以是一个抽象类,其中包含compute() 方法,并且所有子类都可以有自己的实现。

所以以后你可以做这样的事情,

ItemBase ib = new Added();
ib.changed = new Provider(ib);
ib.changed.compute();

现在,当您在ib.changed 上调用计算方法时,它将执行Added 类的计算实现。


在你的情况下,由于基类,添加一个实例变量来区分ProviderCompany。类似于boolean 标志或int

然后,您可以创建 if 语句,而不是使用 dueToBase instanceof Provider。所以你更新的伪代码将减少到几行。像这样的,

doSomething(){
      if(dueToBase.isProvider) {
         algorithm1(); //execute if Provider
      } else { 
         algorithm2(); //execute if Company
      }
}

现在选择计算的复杂性将由抽象模式处理,然后您只需要担心它是公司还是提供商。

【讨论】:

  • 我了解多态性概念,但我的问题是“如何处理嵌套条件以选择适当的操作”。
  • 正如你之前提到的,在现实世界中你不应该检查 instanceof 来执行一些代码。该方法应该被自然调用。我想 ItemBase 和 DueToBase 的设计需要更加清晰。如果需求摆在我们面前,我们只能调试设计,需求是指系统的整个描述:(
  • 我认为这解决了问题,您使用的是 2 种策略模式,在其中您将拥有两个可用特定类的特定实现。除非你不能抽象出相关部分的算法。
  • 我不好的是我在描述中提到了继承,这可能是一个糟糕的概念。问题是如何划分/安排嵌套的 if 子句以使用 OOP 选择特定操作。
  • @GriffinHeart 我正在考虑将在 ItemBase 和 DueToBase 的特定组合上选择的策略模式,但如果我在 DueToBase 下添加另一层嵌套 if 子句,它会变得混乱。有没有更好的解决方案?
【解决方案2】:

更好的方法是:

interface Algorithm {

    void executeAlgorithm();

}

并且有实现算法接口的类,而不是函数。算法1、算法2、算法3等。

还有桌子:

Algorithm[,] algorithmTable = { { new Algorithm1(), new Algorithm2() },
                                { new Algorithm3(), new Algorithm4() },
                                { new Algorithm5(), new Algorithm6() }
                              };

还有地图

Map< Class<?> , Integer > itemBaseMap = new HashMap<>();

Map< Class<?> , Integer > dueToBaseMap = new HashMap<>();

然后在某个地方构建这个地图

itemBaseMap.add( Canceled.class , 0 );
itemBaseMap.add( Modified.class , 1 );
itemBaseMap.add( Added.class , 2 );

dueToBaseMap.add( Provider.class, 0 );
dueToBaseMap.add( Company.class, 1 );

在doSomething方法中你可以写

void doSomething( ItemBase itemBase, DueToBase dueToBase ) {
    Integer itemBaseIndex = itemBaseMap.get( itemBase.getClass() );
    Integer dueToBaseIndex = dueToBaseMap.get( dueToBase.getClass() );

    Algorithm algorithm = algorithmTable[ itemBaseIndex, dueToBaseIndex ];

    algorithm.executeAlgorithm();
}

【讨论】:

  • 这比我在这里写的要好,因为在这个答案中算法接口不依赖于dueToBase或任何东西。
【解决方案3】:

我会说策略模式

abstract class ItemBase {
  public DueToBase myDueToBase;
  public void partOfTheAlgorithmThatOnlySpecificIBKnows();
}

class Modified extends ItemBase {
  public void partOfTheAlgorithmThatOnlySpecificIBKnows() {
     //stuff only Modified knows
  }
}


abstract class DueToBase {
    public void partOfTheAlgorithmThatOnlySpecificDTBKnows();
}

class Provider extends DueToBase {
 //relevant code
  public ItemBase myItemBase;
  public void partOfTheAlgorithmThatOnlySpecificDTBKnows(){
       //stuff only provider knows
  }

  public void compute() {
       //you can also pass this but pointless since you all ready have the reference
       myItemBase.partOfTheAlgorithmThatOnlySpecificIBKnows();
       //some more code
  }
}

ItemBase ib = new Added();
ib.changed = new Provider(ib);
ib.changed.compute();

在示例中,这将调用:

1. compute on Provider
2. part of the algorithm that Modified knows how to calculate
3. rest of the code for the algorithm

所以在compute 函数中,您拥有继承类所需的所有特定方法,并且您可以在compute() 函数中改变算法。

如果这不能解决您的问题,您可能只需要根据 Owl 所说的需求来设计一个新设计。


也没有 ifs,但有更多方法,您可以在其中做与 ifs 相同的事情,您只是让继承机制为您完成。

【讨论】:

  • 这将是一个完美的解决方案,以防 ItemBase 具有独立的算法部分并且我们不关心将哪种类型的实例分配给 myItemBase,因此我们可以忽略。在我的情况下,重要的是要知道哪个 ItemBase 派生类分配给 myItemBase 属性。 ...public void compute() { if(this.myItemBase is Cancelled) doA(); else if(this.myItemBase is Modified) doB(); else doC(); }
  • hmm...您可以解决将this 传递给DueToBase 的问题,如果它在figureWhatToDo() 上的canceled 你调用myDueToBase.doA(),则在this.myItemBase.figureWhatToDo() 中有myDueToBase.doA(),重复其他人跨度>
【解决方案4】:

你可以这样做:

interface Algorithm {
    void executeAlgorithm(DueToBase dueToBase);
}

还有地图

Map<Class, Algorithm> algorithmMap = new HashMap<Class, Algorithm>();

每个算法都有类

例如:

/**
  * this class is, for example, when itemBase instanceof Cancelled 
  */
class Algorithm1 implements Algorithm {

    public void executeAlgorithm(DueToBase dueToBase) {
        if ( dueToBase instanceof Provider ) {
            someAlgorithm();  // the algorithm specified somewhere, for provider
        } else if ( dueToBase instanceof Company ) {
            anotherAlgorithm(); // the algorithm or Company.
    }

    // this someAlgorithm() and anotherAlgorithm() are not same for different Algorithm classes
}

您必须在某个地方构建 algorithmMap。

algorithmMap.add( Cancelled.class , new Algorithm1() );
algorithmMap.add( Modified.class , new Algorithm2() );
algorithmMap.add( Added.class , new Algorithm3() );

并且在 doSomething 方法中,您不必编写 if-else 块

doSomething() {
    Algorithm algorithm = algorithmMap.get( itemBase.getClass() );

    algorithm.executeAlgorithm(dueToBase);
}

在我看来,这是解决这个问题的一个很好的 oop 解决方案。

【讨论】:

  • 如果dueToBase instanceof 变种很多,这个解决方案也会很糟糕。在这种情况下,您可以在 doSomething 方法(另一个 hashMap 和算法)中执行相同的逻辑。或者你可以做chain of responsibility,每个处理程序都会检查一个dueToBase instanceof。
猜你喜欢
  • 1970-01-01
  • 2011-10-11
  • 2015-08-24
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多