код посередине другой, все остальное тоже самое - PullRequest
0 голосов
/ 19 октября 2011

У меня часто бывает ситуация, когда мне нужно сделать:

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 ]

2 голосов
/ 19 октября 2011

Полиморфизм и, возможно, абстракция и инкапсуляция - ваши друзья здесь.

Вы должны уточнить, какие инструкции у вас есть на .... // do some things части. Если вы всегда используете одну и ту же информацию, но делаете с ней разные вещи, решение довольно просто, используя простой полиморфизм. Смотрите мой первый пересмотр этого ответа. Я предполагаю, что вам нужна разная информация для выполнения конкретных задач в каждом конкретном случае.

Вы также не указали, находятся ли эти функции в одном классе / модуле или нет. Если это не так, вы можете использовать наследование, чтобы разделить общие части и полиморфизм, чтобы ввести другое поведение в конкретной части. Если они находятся в одном классе, вам не нужны ни наследование, ни полиморфизм.


В разных классах

С учетом того, что вы задаете вопрос, который может потребоваться для вызова функций с разными сигнатурами в зависимости от подкласса реализации (например, передача a или b в качестве параметра в зависимости от случая), и предполагая, что вам нужно что-то сделать с промежуточными локальными переменными (например, a и b) в конкретных реализациях:

Короткая версия : Полиморфизм + Инкапсуляция: передать все возможные параметры in & 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 голос
/ 19 октября 2011

Ну, не повторяйся .Мое золотое правило (которое, по общему признанию, я нарушаю время от времени) основано на правиле ZOI : весь код должен жить ровно ноль, один или бесконечные времена.Если вы видите повторенный код, вам следует преобразовать его в общего предка.

Тем не менее, невозможно дать вам определенный ответ, как выполнить рефакторинг вашего кода;Есть бесконечные способы сделать это.Например, если a1() и a2() находятся в разных классах, вы можете использовать полиморфизм.Если они живут в одном классе, вы можете создать функцию, которая получает анонимную функцию в качестве параметра, а затем a1() и a2() являются просто обертками для этой функции.Также можно использовать параметр (дрожь) для изменения поведения функции.

0 голосов
/ 19 октября 2011

Это громко кричит для шаблона проектирования "Шаблонный метод"

Общая часть находится в суперклассе:

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

}

Для каждого специального решения, которое вы реализуете подкласс, с определенным поведением.

Если вы поместите их все в коллекцию, вы можете выполнить итерацию по ним и всегда вызывать общий метод, а класс evry делаетэто магия.;)

надеюсь, это поможет

0 голосов
/ 19 октября 2011

Вы можете решить это одним из 2 способов. И a1, и a2 будут вызывать a3. a3 сделает общий код и:
1. вызвать функцию, полученную в качестве параметра, которая выполняет либо среднюю часть a1, либо среднюю часть a2 (и они передадут правильный параметр),
- или -
2. получить флаг (например, логический), который сообщит ему, какую часть ему нужно выполнить, и с помощью оператора if выполнит правильный код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...