Why use method local abstract inner classes

后端 未结 10 1791
名媛妹妹
名媛妹妹 2021-02-05 04:45

One of the legal modifiers you can use with method local inner classes is abstract.

For example:

public class Outer {
    public void method(){
        a         


        
10条回答
  •  南笙
    南笙 (楼主)
    2021-02-05 05:16

    I think it can be useful to reduce the scope of methods in certain conditions.

    For exemple, I use it in unit tests. Sometimes you need an utility method to reduce the verbosity of a test. But this utility method may be related to the current test dataset, and can't be reused outside of this test.

      @Test
      public void facetting_is_impacted_by_filtering() {
        // given
        String userId = "cd01d6b08bc29b012789ff0d05f8e8f1";
        DocumentSolrClient client = solrClientsHolder.getDocumentClient(userId);
        //
        final SolrDocument doc1 = createDocument(userId);
        doc1.setAuthorName("AuthorName1");
        doc1.setType("Type1");
        doc1.setUserTags(Arrays.asList("UserTag1", "UserTag1bis","UserTag1bisbis"));
        doc1.setSenderTags(Arrays.asList("SenderTag1", "SenderTag1bis"));
        doc1.setCreationDate( new Date(EnumDateRange.CURRENT_DAY.getBegin().getTime()+1000) );
        doc1.setLocation(DocumentLocation.INBOX);
        client.index(doc1);
        //
        final SolrDocument doc2 = createDocument(userId);
        doc2.setAuthorName("AuthorName2");
        doc2.setType("Type2");
        doc2.setUserTags(Arrays.asList("UserTag2"));
        doc2.setSenderTags(Arrays.asList("SenderTag2"));
        doc2.setCreationDate( new Date(1000) ); // cree il y a tres longtemps
        doc2.setLocation(DocumentLocation.SAFE);
        client.index(doc2);
        //
        final List facettedRanges = Arrays.asList(
                EnumDateRange.CURRENT_DAY,
                EnumDateRange.CURRENT_YEAR,
                EnumDateRange.BEFORE_CURRENT_YEAR
        );
        class TestUtils {
          ApiSearchRequest baseFacettingRequest(String userId) {
            ApiSearchRequest req = new ApiSearchRequest(userId);
            req.setDocumentTypeFacets(true);
            req.setSenderNameFacets(true);
            req.setSenderTagsFacets(true);
            req.setUserTagsFacets(true);
            req.addDateCreationFacets(facettedRanges);
            return req;
          }
          void assertDoc1FacettingResult(ApiSearchResponse res) {
            assertThat(res.getDocuments().size()).isEqualTo(1);
            assertThat(res.getDocumentTypeFacets().get().getCounts()).hasSize(1);
            assertThat(res.getSenderNameFacets().get().getCounts()).hasSize(1);
            assertThat(res.getSenderTagsFacets().get().getCounts()).hasSize(2);
            assertThat(res.getUserTagsFacets().get().getCounts()).hasSize(3);
            assertThat(res.getDateCreationFacets().get().getCounts()).isEqualTo( computeExpectedDateFacettingResult( Arrays.asList(doc1),facettedRanges) );
          }
          void assertDoc2FacettingResult(ApiSearchResponse res) {
            assertThat(res.getDocuments().size()).isEqualTo(1);
            assertThat(res.getDocumentTypeFacets().get().getCounts()).hasSize(1);
            assertThat(res.getSenderNameFacets().get().getCounts()).hasSize(1);
            assertThat(res.getSenderTagsFacets().get().getCounts()).hasSize(1);
            assertThat(res.getUserTagsFacets().get().getCounts()).hasSize(1);
            assertThat(res.getDateCreationFacets().get().getCounts()).isEqualTo( computeExpectedDateFacettingResult( Arrays.asList(doc2),facettedRanges) );
          }
        }
        TestUtils utils = new TestUtils();
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // when
        ApiSearchRequest req = utils.baseFacettingRequest(userId);
        ApiSearchResponse res = documentSearchService.search(req);
        // then
        assertThat(res.getDocuments().size()).isEqualTo(2);
        assertThat(res.getDocumentTypeFacets().get().getCounts()).hasSize(2);
        assertThat(res.getSenderNameFacets().get().getCounts()).hasSize(2);
        assertThat(res.getSenderTagsFacets().get().getCounts()).hasSize(3);
        assertThat(res.getUserTagsFacets().get().getCounts()).hasSize(4);
        assertThat(res.getDateCreationFacets().get().getCounts()).isEqualTo( computeExpectedDateFacettingResult( Arrays.asList(doc1,doc2),facettedRanges) );
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // when
        req = utils.baseFacettingRequest(userId);
        req.addLocation(DocumentLocation.SAFE);
        res = documentSearchService.search(req);
        // then
        utils.assertDoc2FacettingResult(res);
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // when
        req = utils.baseFacettingRequest(userId);
        req.addUserTag("UserTag1");
        res = documentSearchService.search(req);
        // then
        utils.assertDoc1FacettingResult(res);
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // when
        req = utils.baseFacettingRequest(userId);
        req.addSenderTag("SenderTag2");
        res = documentSearchService.search(req);
        // then
        utils.assertDoc2FacettingResult(res);
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // when
        req = utils.baseFacettingRequest(userId);
        req.setDocumentType("Type1");
        res = documentSearchService.search(req);
        // then
        utils.assertDoc1FacettingResult(res);
      }
    

    In this real-life exemple, I could have done a regular inner class, but someone could have been tempted to reuse it in other tests, while it was not designed to.

    By the way, you will notice the ability to "capture" the dataset build in the test directly inside the utility class. Using a regular inner class, it couldn't work without creating the test specific dataset outside the test too... so you end up with a lot of things shared with other tests, while they are used (should be used) by only one.


    In the end, I don't think a feature permitting to reduce the visibility is useless.

    You can build a perfectly working application without using encapsulation at all, and can argue the same thing, saying the private modifier is useless...

    But yes, the private modifier is certainly more useful than method local innerclasses ;)

提交回复
热议问题