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

发布于 2024-12-10 22:10:48 字数 404 浏览 1 评论 0原文

我经常遇到一种需要做的情况:

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 (此类型)执行此操作,否则执行其他不同的操作?这似乎也不是一个很好的解决方案。

I often have a situation where I need to do:

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;
}

I feel like I am repeating myself, yet where I have ...., the methods are different, have different signatures, etc..

What do people normally do? Add an if (this type) do this stuff, else do the other stuff that is different? It doesn't seem like a very good solution either.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

迷你仙 2024-12-17 22:10:48

多态性以及可能的抽象和封装是你的朋友。

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

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


在不同的类中

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

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

长版
我将中间状态存储在泛型类的成员中,并将其传递给实现方法。或者,您可以从实现方法中获取状态,而不是将其作为参数传递。然后,您可以创建它的两个子类来实现 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();
  }
}

Polymorphism and possibly abstraction and encapsulation are your friends here.

You should specify better what kind of instructions you have on the .... // do some things part. If you're always using the same information, but doing different things with it, the solution is fairly easy using simple polymorphism. See my first revision of this answer. I'll assume you need different information to do the specific tasks in each case.

You also didn't specify if those functions are in the same class/module or not. If they are not, you can use inheritance to share the common parts and polymorphism to introduce different behavior in the specific part. If they are in the same class you don't need inheritance nor polymorphism.


In different classes

Taking into account you're stating in the question that you might need to make calls to functions with different signature depending on the implementation subclass (for instance, passing a or b as parameter depending on the case), and assuming you need to do something with the intermediate local variables (i.e. a and b) in the specific implementations:

Short version: Polymorphism+Encapsulation: Pass all the possible in & out parameters that every subclass might need to the abstract function. Might be less painful if you encapsulate them in an object.

Long Version
I'd store intermediate state in generic class' member, and pass it to the implementation methods. Alternatively you could grab the State from the implementation methods instead of passing it as an argument. Then, you can make two subclasses of it implementing the doSpecificStuff(State) method, and grabbing the needed parameters from the intermediate state in the superclass. If needed by the superclass, subclasses might also modify state.

(Java specifics next, sorry)

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();
   }
}

In the same class

Another possibility would be making the preProcess() method return a State variable, and use it inthe implementations of a1() and 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();
  }
}
别闹i 2024-12-17 22:10:48

好吧,不要重复自己。我的黄金法则(诚然,我有时会打破它)是基于 ZOI 规则:所有代码必须恰好存在零次、一次或无限次。如果您看到代码重复,您应该将其重构为共同的祖先。

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

Well, don't repeat yourself. My golden rule (which admittedly I break from time on time) is based on the ZOI rule: all code must live exactly zero, one or infinite times. If you see code repeated, you should refactor that into a common ancestor.

That said, it is not possible to give you a definite answer how to refactor your code; there are infinite ways to do this. For example, if a1() and a2() reside in different classes then you can use polymorphism. If they live in the same class, you can create a function that receives an anonymous function as parameter and then a1() and a2() are just wrappers to that function. Using a (shudder) parameter to change the function behavior can be used, too.

剑心龙吟 2024-12-17 22:10:48

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

You can solve this in one of 2 ways. Both a1 and a2 will call a3. a3 will do the shared code, and:
1. call a function that it receives as a parameter, which does either the middle part of a1 or the middle part of a2 (and they will pass the correct parameter),
- or -
2. receive a flag (e.g. boolean), which will tell it which part it needs to do, and using an if statement will execute the correct code.

悲喜皆因你 2024-12-17 22:10:48

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

一般部分在超类中:

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();
}

}

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

如果将它们全部放入集合中,则可以迭代它们并始终调用通用方法,每个类都会发挥其魔力。 ;)

希望这有帮助

This screams out loud for the design pattern "Template Method"

The general part is in the super class:

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);
}

The spezific part is in the subclass:

package patterns.templatemethod;

public class ConcreteA extends AbstractSuper {

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

}

For every spezific solution you implement a subclass, with the specific behavior.

If you put them all in an Collection, you can iterate over them and call always the common method and evry class does it's magic. ;)

hope this helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文