Lesson 11 discussed the distinction between static nested classes and inner classes. A third type of nested class is the anonymous inner class. An anonymous inner class allows you to dynamically define unnamed class implementations within a method body. Understanding the syntax and nuances of anonymous inner classes can be daunting. But once you understand anonymous inner classes, your use of them can make your code more concise and easy to understand. Take the body of the MockAch class (i.e., all the method definitions) and insert it as the first line of code in testTransferFromBank. Immediately preceding all that code, add the line: Ach mockAch = new Ach() { Then terminate the mock Ach method definitions with a closing brace and semicolon. The transformed test:[3]
public void testTransferFromBank() { Ach mockAch = new Ach() { public AchResponse issueDebit( AchCredentials credentials, AchTransactionData data) { Assert.assertTrue( data.account.equals(AccountTest.ACCOUNT_NUMBER)); Assert.assertTrue(data.aba.equals(AccountTest.ABA)); AchResponse response = new AchResponse(); response.timestamp = new Date(); response.traceCode = "1"; response.status = AchStatus.SUCCESS; return response; } public AchResponse markTransactionAsNSF( AchCredentials credentials, AchTransactionData data, String traceCode) { return null; } public AchResponse refundTransaction(AchCredentials credentials, AchTransactionData data, String traceCode) { return null; } public AchResponse issueCredit(AchCredentials credentials, AchTransactionData data) { return null; } public AchResponse voidSameDayTransaction( AchCredentials credentials, AchTransactionData data, String traceCode) { return null; } public AchResponse queryTransactionStatus ( AchCredentials credentials, AchTransactionData data, String traceCode) { return null; } }; account.setAch(mockAch); final BigDecimal amount = new BigDecimal("50.00"); account.transferFromBank(amount); assertEquals(amount, account.getBalance()); }
The line of code: Ach mockAch = new Ach() { creates a reference named mockAch of the interface type Ach. The right-hand side instantiates an Ach object using new. But Ach is an interfacehow can you instantiate an interface? Java is allowing you to dynamically provide an implementation for the Ach interface and at the same time create an instance with that implementation. You provide the implementation in a block of code immediately after the constructor call (new Ach()) but before the semicolon that terminates the statement. The implementation supplied in the block is of Ach type, but it has no specific class name. It is anonymous. You can send messages to this object, store it, or pass it as a parameter, just as you might with an object of a named Ach implementation such as MockAch. Make sure that your tests pass, but don't delete MockAch just yet. As you've seen, anonymous inner classes can be useful when building mocks for testing purposes. Swing applications (see Additional Lesson I) and multithreading (see Lesson 13) often make heavy use of anonymous inner classes. Admittedly, it's still a bit difficult to follow what's going on in testTransferFromBank. The test method is now long and cluttered. The next section on adapters shows how to improve on things. |