2015-12-01 3 views
4

Как вы примирились с использованием статических заводских методов и насмешек?Статические методы фабрики и насмешливость

Многие люди просто скажут: не используйте статические заводские методы, вместо этого используйте DI.

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

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

Как только вы идете new Option(null), вы создаете новый объект-объект, вы не можете возвращать один и тот же объект снова и снова.

Аналогичным вариантом использования является Integer.valueOf(), который будет повторно использовать целые объекты для значений ниже 128. Невозможно обойтись без использования статического метода фабрики.

Еще одно преимущество заключается в том, что методы фабрики более наглядны, чем ключевое слово new.

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

спасибо.

+1

Зачем вам нужно «издеваться» над опцией? Способы фабрики 'static' для таких тривиальных классов прекрасны. –

+0

Забавно, что вы специально раскрываете «Вариант» Scala в качестве примера здесь, так как * Scala не имеет понятия «статические элементы» *. 'Option.apply()' - это экземпляр (нестатический) метод для обычного (экземпляра) объекта. В JVM объект экземпляра хранится в статическом поле 'Option.MODULE', поэтому вызов' Option (1) 'фактически расширяется до типа Option.MODULE.apply (1)'. Это очень похоже на 'System.out.println()', где 'out' также является статическим полем, но вы можете изменить через' System.setOut() '. Другими словами, у вас нет * * использовать статические методы для чего-либо ... – DaoWen

ответ

1

Поскольку это теоретический вопрос, я сделаю теоретический ответ. Парадигма фабрики является отправной точкой для другой теории: Инъекции. Если ваши созданные объекты вводятся, когда это необходимо, тогда вам нужно только вводить свои издеваемые объекты для выполнения всех ваших тестов. Там много хороших книг/веб-страниц, которые могут помочь вам начать с этого.

2

Изношение статических методов возможно с использованием PowerMock. Рассмотрим следующий пример из их Wiki page:

@Test 
public void testRegisterService() throws Exception { 
    long expectedId = 42; 

    // We create a new instance of test class under test as usually. 
    ServiceRegistartor tested = new ServiceRegistartor(); 

    // This is the way to tell PowerMock to mock all static methods of a 
    // given class 
    mockStatic(IdGenerator.class); 

    /* 
    * The static method call to IdGenerator.generateNewId() expectation. 
    * This is why we need PowerMock. 
    */ 
    expect(IdGenerator.generateNewId()).andReturn(expectedId); 

    // Note how we replay the class, not the instance! 
    replay(IdGenerator.class); 

    long actualId = tested.registerService(new Object()); 

    // Note how we verify the class, not the instance! 
    verify(IdGenerator.class); 

    // Assert that the ID is correct 
    assertEquals(expectedId, actualId); 
} 

Это даже можно издеваться только один конкретный метод, а остальное оставьте как есть, используя partial mocking.

0

Мы просто избегаем использования статических заводских методов и вместо этого используем инъекцию зависимостей.

Если Java был разработан с DI в виде с самого начала, то Integer.valueOf() бы:

  • integerType.valueOf() где integerType бы введенную зависимость, или

  • typeSystem.getInteger().valueOf() где typeSystem будет введенная зависимость, или

  • environment.getTypeSystem().getInteger().getFactory(), где environment будет представлять собой n введенная зависимость.

Нет ничего, что вы можете сделать со статическими фабриками, которые вы не можете сделать с усердным использованием инъекции зависимостей.

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

Например, вы можете обернуть System.out в некоторых StandardConsole объекте реализации некоторых Console интерфейса, и ввести этот интерфейс Console как зависимость в приложение.

(И если вы сделаете это, я бы даже добавить, что вы можете продолжить и настроить систему управления версиями, чтобы отклонить любые попытки совершить код, содержащий строку «System.out». [Злобная ухмылка])

+0

Как бы вы ввели JSF 'FacesContext' или JasperRunManager Report Jasper Report, которые обычно получают из статических заводских методов? –

+0

@ Rogério easy, создайте требование конструктора в 'class', которое имеет зависимость от' JasperRunManager' и сообщит вам, что инфраструктура DI получит экземпляр с соответствующей фабрики 'static'. Это очень часто встречается с Spring, например ', где вы можете просто аннотировать метод, который возвращает вызов фабрике' static' с '@ Bean'. –

+0

@ Rogério Я поправился, чтобы ответить на вашу озабоченность. –

1

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

Это, если я сделать хочу или нужно их издеваться, тогда я просто сделаю это. Например, подумайте, что вы тестируете веб-приложение на основе JSF, и хотите высмеять объект javax.faces.context.FacesContext. Я хотел бы написать следующее испытание, используя библиотеку JMockit (который я случайно развиваться):

@Test 
public void exampleTest(@Mocked final FacesContext ctx) { 
    // Call the code under test, which will at some point 
    // call FacesContext.getCurrentInstance(), then add an 
    // error message for display in the web page. 

    new Verifications() {{ 
     FacesMessage msg; 
     ctx.addMessage(null, msg = withCapture()); 

     assertEquals("The expected error message.", msg.getSummary()); 
     assertNotNull(msg.getDetail()); 
    }}; 
} 

В этом примере Faces.getCurrentInstance() является статическим методом завода, который будет автоматически возвращать макет FacesContext экземпляра раз в класс издевается.

+0

Хорошо, из того, что я вижу, вы один из разработчиков JMockit, который замечателен, поэтому Kudos для этого. Но, пожалуйста, поймите, что у других могут быть разные мнения, и, пожалуйста, не обидитесь на это. Мое мнение состоит в том, что издевательства - это потрясающий практический компромисс, когда вокруг них нет другого пути, но лучший разработанный код - это код, который не нуждается в издевательствах. (Хотя первое предложение, которое вы написали, похоже, предвосхищает это.) –

Смежные вопросы