В чем разница между шаблоном стратегии и внедрением зависимостей?

'возврат fabs (-b) < ЭПСИЛОН;

Это прекрасно если:

  • порядок величины Ваших исходных данных не изменяется очень
  • , очень небольшие числа противоположных знаков можно рассматривать как равные

, Но иначе он приведет Вас в проблему. Числа двойной точности имеют разрешение приблизительно 16 десятичных разрядов. Если эти два числа, которые Вы сравниваете, больше в величине, чем EPSILON*1.0E16, то Вы могли бы также говорить:

return a==b;

я исследую другой подход, который предполагает, что необходимо волноваться о первом выпуске и предположить, что второе прекрасно приложение. Решение было бы чем-то как:

#define VERYSMALL  (1.0E-150)
#define EPSILON    (1.0E-8)
bool AreSame(double a, double b)
{
    double absDiff = fabs(a - b);
    if (absDiff < VERYSMALL)
    {
        return true;
    }

    double maxAbs  = max(fabs(a) - fabs(b));
    return (absDiff/maxAbs) < EPSILON;
}

Это дорого в вычислительном отношении, но это иногда, что требуется. Это - то, что мы должны сделать в моей компании, потому что мы имеем дело с технической библиотекой, и исходные данные могут варьироваться несколькими дюжинами порядков величины.

Так или иначе, точка - это (и относится практически к каждой проблеме программирования): Оцените, каковы Ваши потребности являются, затем предлагают решение для обращения к потребностям - не предполагают, что легкий ответ обратится потребностям. Если после Вашей оценки Вы находите, что fabs(a-b) < EPSILON будет достаточен, прекрасный - используют его! Но знайте о его недостатках и других возможных решениях также.

91
задан BalusC 17 December 2010 в 16:16
поделиться

2 ответа

Вы можете использовать DI в качестве шаблона стратегии, так что вы можете поменять местами алгоритм, необходимый для каждого клиента, но DI может выйти за рамки этого, поскольку это способ просто разделить части приложение, которое не было бы частью шаблона стратегии.

Было бы рискованно говорить, что DI - это просто переименованный шаблон стратегии, поскольку это начинает размывать то, для чего на самом деле шаблон стратегии, ИМО.

27
ответ дан 24 November 2019 в 06:46
поделиться

Стратегии - это вещи более высокого уровня, которые используются для изменения способа вычислений. С внедрением зависимостей вы можете изменить не только способ вычисления, но и то, что там есть.

Для меня это становится ясным при использовании модульных тестов. Для выполнения производственного кода все данные скрыты (т. Е. Закрыты или защищены); тогда как в модульных тестах большая часть данных является общедоступной, поэтому я могу просматривать ее с помощью утверждений.


Пример стратегии:

public class Cosine {
  private CalcStrategy strat;

  // Constructor - strategy passed in as a type of DI
  public Cosine(CalcStrategy s) {
    strat = s;
  }
}

public abstract class CalcStrategy {
  public double goFigure(double angle);
}

public class RadianStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}
public class DegreeStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}

Обратите внимание, что нет общедоступных данных, различающихся между стратегиями. Нет и других методов. Обе стратегии используют одни и те же функции и сигнатуры.


Теперь о внедрении зависимостей:

public class Cosine {
  private Calc strat;

  // Constructor - Dependency Injection.
  public Cosine(Calc s) {
    strat = s;
  }
}

public class Calc {
  private int numPasses = 0;
  private double total = 0;
  private double intermediate = 0;

  public double goFigure(double angle) {
    return(...);
}

public class CalcTestDouble extends Calc {
  // NOTICE THE PUBLIC DATA.
  public int numPasses = 0;
  public double total = 0;
  public double intermediate = 0;
  public double goFigure(double angle) {
    return (...);
  }
}

Использование:

public CosineTest {

  @Test
  public void testGoFigure() {
    // Setup
    CalcTestDouble calc = new CalcTestDouble();
    Cosine instance = new Cosine(calc);

    // Exercise
    double actualAnswer = instance.goFigure(0.0);

    // Verify
    double tolerance = ...;
    double expectedAnswer = ...;
    assertEquals("GoFigure didn't work!", expectedAnswer,
         actualAnswer, tolerance);

    int expectedNumPasses = ...;
    assertEquals("GoFigure had wrong number passes!",
        expectedNumPasses, calc.numPasses);

    double expectedIntermediate = ...;
    assertEquals("GoFigure had wrong intermediate values!",
        expectedIntermediate, calc.intermediate, tolerance);
  }
}

Обратите внимание на последние 2 проверки. Они использовали общедоступные данные в тестовом двойнике, который был введен в тестируемый класс. Я не мог сделать это с производственным кодом из-за данных Для выполнения производственного кода все данные скрыты (т. Е. Закрыты или защищены); тогда как в модульных тестах большая часть данных является общедоступной, поэтому я могу просматривать ее с помощью утверждений.


Пример стратегии:

public class Cosine {
  private CalcStrategy strat;

  // Constructor - strategy passed in as a type of DI
  public Cosine(CalcStrategy s) {
    strat = s;
  }
}

public abstract class CalcStrategy {
  public double goFigure(double angle);
}

public class RadianStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}
public class DegreeStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}

Обратите внимание, что нет общедоступных данных, различающихся между стратегиями. Нет и других методов. Обе стратегии используют одни и те же функции и сигнатуры.


Теперь о внедрении зависимостей:

public class Cosine {
  private Calc strat;

  // Constructor - Dependency Injection.
  public Cosine(Calc s) {
    strat = s;
  }
}

public class Calc {
  private int numPasses = 0;
  private double total = 0;
  private double intermediate = 0;

  public double goFigure(double angle) {
    return(...);
}

public class CalcTestDouble extends Calc {
  // NOTICE THE PUBLIC DATA.
  public int numPasses = 0;
  public double total = 0;
  public double intermediate = 0;
  public double goFigure(double angle) {
    return (...);
  }
}

Использование:

public CosineTest {

  @Test
  public void testGoFigure() {
    // Setup
    CalcTestDouble calc = new CalcTestDouble();
    Cosine instance = new Cosine(calc);

    // Exercise
    double actualAnswer = instance.goFigure(0.0);

    // Verify
    double tolerance = ...;
    double expectedAnswer = ...;
    assertEquals("GoFigure didn't work!", expectedAnswer,
         actualAnswer, tolerance);

    int expectedNumPasses = ...;
    assertEquals("GoFigure had wrong number passes!",
        expectedNumPasses, calc.numPasses);

    double expectedIntermediate = ...;
    assertEquals("GoFigure had wrong intermediate values!",
        expectedIntermediate, calc.intermediate, tolerance);
  }
}

Обратите внимание на последние 2 проверки. Они использовали общедоступные данные в тестовом двойнике, который был введен в тестируемый класс. Я не мог сделать это с производственным кодом из-за данных Для выполнения производственного кода все данные скрыты (т. Е. Закрыты или защищены); тогда как в модульных тестах большая часть данных является общедоступной, поэтому я могу просматривать ее с помощью утверждений.


Пример стратегии:

public class Cosine {
  private CalcStrategy strat;

  // Constructor - strategy passed in as a type of DI
  public Cosine(CalcStrategy s) {
    strat = s;
  }
}

public abstract class CalcStrategy {
  public double goFigure(double angle);
}

public class RadianStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}
public class DegreeStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}

Обратите внимание, что нет общедоступных данных, различающихся между стратегиями. Нет и других методов. Обе стратегии используют одни и те же функции и сигнатуры.


Теперь о внедрении зависимостей:

public class Cosine {
  private Calc strat;

  // Constructor - Dependency Injection.
  public Cosine(Calc s) {
    strat = s;
  }
}

public class Calc {
  private int numPasses = 0;
  private double total = 0;
  private double intermediate = 0;

  public double goFigure(double angle) {
    return(...);
}

public class CalcTestDouble extends Calc {
  // NOTICE THE PUBLIC DATA.
  public int numPasses = 0;
  public double total = 0;
  public double intermediate = 0;
  public double goFigure(double angle) {
    return (...);
  }
}

Использование:

public CosineTest {

  @Test
  public void testGoFigure() {
    // Setup
    CalcTestDouble calc = new CalcTestDouble();
    Cosine instance = new Cosine(calc);

    // Exercise
    double actualAnswer = instance.goFigure(0.0);

    // Verify
    double tolerance = ...;
    double expectedAnswer = ...;
    assertEquals("GoFigure didn't work!", expectedAnswer,
         actualAnswer, tolerance);

    int expectedNumPasses = ...;
    assertEquals("GoFigure had wrong number passes!",
        expectedNumPasses, calc.numPasses);

    double expectedIntermediate = ...;
    assertEquals("GoFigure had wrong intermediate values!",
        expectedIntermediate, calc.intermediate, tolerance);
  }
}

Обратите внимание на последние 2 проверки. Они использовали общедоступные данные в тестовом двойнике, который был введен в тестируемый класс. Я не мог сделать это с производственным кодом из-за данных

public class Cosine {
  private CalcStrategy strat;

  // Constructor - strategy passed in as a type of DI
  public Cosine(CalcStrategy s) {
    strat = s;
  }
}

public abstract class CalcStrategy {
  public double goFigure(double angle);
}

public class RadianStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}
public class DegreeStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}

Обратите внимание, что нет общедоступных данных, различающихся между стратегиями. Нет и других методов. Обе стратегии используют одни и те же функции и сигнатуры.


Теперь о внедрении зависимостей:

public class Cosine {
  private Calc strat;

  // Constructor - Dependency Injection.
  public Cosine(Calc s) {
    strat = s;
  }
}

public class Calc {
  private int numPasses = 0;
  private double total = 0;
  private double intermediate = 0;

  public double goFigure(double angle) {
    return(...);
}

public class CalcTestDouble extends Calc {
  // NOTICE THE PUBLIC DATA.
  public int numPasses = 0;
  public double total = 0;
  public double intermediate = 0;
  public double goFigure(double angle) {
    return (...);
  }
}

Использование:

public CosineTest {

  @Test
  public void testGoFigure() {
    // Setup
    CalcTestDouble calc = new CalcTestDouble();
    Cosine instance = new Cosine(calc);

    // Exercise
    double actualAnswer = instance.goFigure(0.0);

    // Verify
    double tolerance = ...;
    double expectedAnswer = ...;
    assertEquals("GoFigure didn't work!", expectedAnswer,
         actualAnswer, tolerance);

    int expectedNumPasses = ...;
    assertEquals("GoFigure had wrong number passes!",
        expectedNumPasses, calc.numPasses);

    double expectedIntermediate = ...;
    assertEquals("GoFigure had wrong intermediate values!",
        expectedIntermediate, calc.intermediate, tolerance);
  }
}

Обратите внимание на последние 2 проверки. Они использовали общедоступные данные в тестовом двойнике, который был введен в тестируемый класс. Я не мог сделать это с производственным кодом из-за данных

public class Cosine {
  private CalcStrategy strat;

  // Constructor - strategy passed in as a type of DI
  public Cosine(CalcStrategy s) {
    strat = s;
  }
}

public abstract class CalcStrategy {
  public double goFigure(double angle);
}

public class RadianStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}
public class DegreeStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}

Обратите внимание, что нет общедоступных данных, различающихся между стратегиями. Нет и других методов. Обе стратегии используют одни и те же функции и сигнатуры.


Теперь о внедрении зависимостей:

public class Cosine {
  private Calc strat;

  // Constructor - Dependency Injection.
  public Cosine(Calc s) {
    strat = s;
  }
}

public class Calc {
  private int numPasses = 0;
  private double total = 0;
  private double intermediate = 0;

  public double goFigure(double angle) {
    return(...);
}

public class CalcTestDouble extends Calc {
  // NOTICE THE PUBLIC DATA.
  public int numPasses = 0;
  public double total = 0;
  public double intermediate = 0;
  public double goFigure(double angle) {
    return (...);
  }
}

Использование:

public CosineTest {

  @Test
  public void testGoFigure() {
    // Setup
    CalcTestDouble calc = new CalcTestDouble();
    Cosine instance = new Cosine(calc);

    // Exercise
    double actualAnswer = instance.goFigure(0.0);

    // Verify
    double tolerance = ...;
    double expectedAnswer = ...;
    assertEquals("GoFigure didn't work!", expectedAnswer,
         actualAnswer, tolerance);

    int expectedNumPasses = ...;
    assertEquals("GoFigure had wrong number passes!",
        expectedNumPasses, calc.numPasses);

    double expectedIntermediate = ...;
    assertEquals("GoFigure had wrong intermediate values!",
        expectedIntermediate, calc.intermediate, tolerance);
  }
}

Обратите внимание на последние 2 проверки. Они использовали общедоступные данные в тестовом двойнике, который был введен в тестируемый класс. Я не мог сделать это с производственным кодом из-за данных принцип сокрытия. Я не хотел, чтобы код тестирования специального назначения был вставлен в производственный код. Общедоступные данные должны относиться к другому классу.

Был введен тестовый двойник. Это отличается от стратегии, поскольку она влияет на данные , а не только на функции.

7
ответ дан 24 November 2019 в 06:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: