中间的代码是不同的,其他一切都是一样的

时间:2011-10-19 14:18:47

标签: oop design-patterns inheritance refactoring polymorphism

我经常遇到需要做的事情:

function a1() {
 a = getA;
 b = getB;
 b.doStuff();
 ....  // do some things
 b.send()
 return a - b;
}

function a2() {
 a = getA;
 b = getB;
 b.doStuff();
 ....  // do some things, but different to above
 b.send()
 return a - b;
}

我觉得我在重复自己,但在....,我的方法不同,有不同的签名等。

人们通常做什么?添加一个if(这种类型)做这个东西,否则做其他不同的东西?它似乎也不是一个很好的解决方案。

4 个答案:

答案 0 :(得分:2)

Polymorphism可能抽象和封装是你的朋友。

您应该更好地指定.... // do some things部分的说明。如果您总是使用相同的信息,但使用它做不同的事情,使用简单的多态性解决方案相当容易。请参阅我对此答案的第一次修订。我假设你需要不同的信息来完成每种情况下的具体任务。

您也没有指定这些函数是否在同一个类/模块中。如果不是,则可以使用继承来共享公共部分和多态,以在特定部分中引入不同的行为。如果它们属于同一个类,则不需要继承或多态。


在不同的班级

考虑到您在问题中说明您可能需要根据实现子类调用具有不同签名的函数(例如,将ab作为参数传递,具体取决于案例),并假设您需要在特定实现中对中间局部变量(即ab)执行某些操作:

短版:多态+封装:将所有可能的传递给& out 每个子类可能需要抽象函数的参数。如果将它们封装在一个对象中,可能会减少痛苦。

长版 我将中间状态存储在泛型类的成员中,并将其传递给实现方法。或者,您可以从实现方法中获取State,而不是将其作为参数传递。然后,您可以使其实现doSpecificStuff(State)方法的两个子类,并从超类中的中间状态中获取所需的参数。如果超类需要,子类也可以修改状态。

(接下来是Java细节,对不起)

public abstract class Generic {
  private State state = new State();
  public void a() {
     preProcess();
     prepareState();
     doSpecificStuf(state);
     clearState();
     return postProcess();
  }
  protected void preProcess(){ 
     a = getA;
     b = getB;
     b.doStuff();
  }
  protected Object postProcess(){ 
     b.send()
     return a - b;
  }
  protected void prepareState(){ 
     state.prepareState(a,b);
  }
  private void clearState() { 
     state.clear();
  }
  protected abstract doSpecificStuf(State state);
}
public class Specific extends Generic { 
   protected doSpecificStuf(State state) { 
       state.getA().doThings();
       state.setB(someCalculation);
   }
}
public class Specific2 extends Generic { 
   protected doSpecificStuf(State state) { 
       state.getB().doThings();
   }
}

在同一课程中

另一种可能性是使preProcess()方法返回State变量,并将其用于a1()a2()的实现中。

public class MyClass {
  protected State preProcess(){ 
     a = getA;
     b = getB;
     b.doStuff();
     return new State(a,b);
  }
  protected Object postProcess(){ 
     b.send()
     return a - b;
  }
  public void a1(){
      State st = preProcess();
      st.getA().doThings();
      State.clear(st);
      return postProcess();
  }
  public void a2(){
      State st = preProcess();
      st.getB().doThings();
      State.clear(st);
      return postProcess();
  }
}

答案 1 :(得分:1)

好吧,don't repeat yourself。我的黄金法则(不可否认,我准时打破)基于ZOI规则:所有代码必须完全为零,一次或无限次。如果你看到重复的代码,你应该将它重构为一个共同的祖先。

那就是说,如何重构代码是不可能给出明确答案的;有无限的方法可以做到这一点。例如,如果a1()a2()位于不同的类中,那么您可以使用多态。如果它们位于同一个类中,您可以创建一个接收匿名函数作为参数的函数,然后a1()a2()只是该函数的包装器。也可以使用(颤抖)参数来改变函数行为。

答案 2 :(得分:0)

您可以通过以下两种方式之一解决此问题。 a1a2都会调用a3a3将执行共享代码,并且:
1.调用它作为参数接收的函数,该函数执行a1的中间部分或a2的中间部分(并且它们将传递正确的参数),
- 或 -
2.接收一个标志(例如布尔值),它将告诉它需要做哪个部分,并使用if语句执行正确的代码。

答案 3 :(得分:0)

这对于“模板方法”的设计模式大声尖叫

一般部分属于超类:

package patterns.templatemethod;

public abstract class AbstractSuper {

public Integer doTheStuff(Integer a, Integer b) {
    Integer x = b.intValue() + a.intValue();

    Integer y = doSpecificStuff(x);

    return b.intValue() * y;
}

protected abstract Integer doSpecificStuff(Integer x);
}

特殊部分在子类中:

package patterns.templatemethod;

public class ConcreteA extends AbstractSuper {

@Override
protected Integer doSpecificStuff(Integer x) {
    return x.intValue() * x.intValue();
}

}

对于每个特定的解决方案,您都要实现具有特定行为的子类。

如果你把它们全部放在一个Collection中,你可以迭代它们并总是调用常用方法,而evry类就是魔术。 ;)

希望这会有所帮助