简体   繁体   English

Java:如何修复多种方法中的代码重复?

[英]Java: How to fix code duplication in multiple methods?

I have some theoretical knowledge related to Design Patterns and now I have some issues to make these info and another ones in action.我有一些与设计模式相关的理论知识,现在我有一些问题来制作这些信息和其他信息。

I have the following 2 methods in my ServiceImpl class:我的ServiceImpl类中有以下 2 个方法:

@Override
public MultipartFile exportA() throws IOException {
    
    // repeated lines-I same as exportB method (code omitted for brevity)
    
    // other lines special to exportA method

    // repeated lines-II same as exportB method (code omitted for brevity)
}
@Override
public MultipartFile exportB() throws IOException {
    
    // repeated lines-I same as exportA method (code omitted for brevity)
    
    // other lines special to exportB method

    // repeated lines-II same as exportA method (code omitted for brevity)
}

As it is shown, there are repeated parts in all of these methods.如图所示,所有这些方法都有重复的部分。 So, should I create 2 methods for repeated lines-I and II, eand then move these code blocks to these newly created 2 methods?那么,我应该为重复的行 I 和 II 创建 2 个方法,然后将这些代码块移动到这些新创建的 2 个方法中吗? Or, is there a better way for Design Patterns?或者,有没有更好的设计模式方法?

If I have well understood your statement, this sounds to me a Builder Pattern that you are looking for.如果我很好地理解了您的陈述,那么在我看来,这就是您正在寻找的Builder Pattern You methods are building a MultipartFile whereas the build process itself depends on 'arguments/parameters' (here I guess sheet file path) and distinct code (the one you referred to as "other lines special to this method").您的方法正在构建MultipartFile而构建过程本身取决于“参数/参数”(这里我猜是工作表文件路径)和不同的代码(您称为“此方法专用的其他行”)。

For that I would create a class MultipartFileBuilder that does the staff and that I would call in each method;为此,我将创建一个类MultipartFileBuilder来处理人员,并且我将在每个方法中调用它; of course, by means of setting the appropriate parameters and "code" each time.当然,通过每次设置适当的参数和“代码”。 The code is simply an implementation of the java.util.function.Consumer<T> functional interface used in the following code (*2) and other parameters are using simple setters as well (here (*1)).该代码只是以下代码 (*2) 中使用的java.util.function.Consumer<T>函数接口的实现,其他参数也使用简单的 setter(此处 (*1))。

Note that I invoked the Consumer<T> as lambda expression here (the c->... construct).请注意,我在这里调用了Consumer<T>作为 lambda 表达式(c->... 构造)。 And note also that the type parameter <T> in Consumer<T> here is a new class I introduced MultipartFileBuildContext to allow multiple information to be passed to the code you are willing to write in each method.还要注意,这里的Consumer<T>中的类型参数<T>是我引入的一个新类MultipartFileBuildContext以允许将多个信息传递给您愿意在每个方法中编写的代码。 I guest the 'sheet' var would be a starting point.我来宾'sheet' var 将是一个起点。 You can add other information if you need to.如果需要,您可以添加其他信息。

To summer up things, this is how the code would look :总结一下,这就是代码的样子:

    
    @Override
    public MultipartFile exportMethodA() throws IOException {
        return new MultipartFileBuilder()
                .setSheetPath("sheetA/path") (*1)
                .setAction(c->{
                    //(*2) do your staff here for method A
                    // the "other lines special to this method"
                    XSSFSheet sheet=c.getSheet()
                    ...
                }).build();
    }

    @Override
    public MultipartFile exportMethodB() throws IOException {
        return new MultipartFileBuilder()
                .setSheetPath("sheetB/path") (*1)
                .setAction(c->{
                    //(*2) do your staff here for method B
                    // the "other lines special to this method"
                    XSSFSheet sheet=c.getSheet()
                    ...
                }).build();
    }

    class MultipartFileBuildContext {
        private XSSFSheet sheet;
        public MultipartFileBuildContext(XSSFSheet sheet){this.sheet=sheet;}
        public String getSheetPath() {
            return sheetPath;
        }
    }
    
    class MultipartFileBuilder {
        String sheetPath; 
        Consumer<MultipartFileBuildContext> action; 

        public String getSheetPath() {
            return sheetPath;
        }

        public MultipartFileBuilder setSheetPath(String sheetPath) {
            this.sheetPath = sheetPath;
            return this;
        }

        public Consumer<MultipartFileBuildContext> getAction() {
            return action;
        }

        public MultipartFileBuilder setAction(Consumer<MultipartFileBuildContext> action) {
            this.action = action;
            return this;
        }
        
        public MockMultipartFile build() {
            // repeated lines
            workbook = new XSSFWorkbook();
            sheet = workbook.createSheet(sheetPath);

            //
            if(action!=null){
                MultipartFileBuildContext c=new MultipartFileBuildContext(sheet);
                action.accept(c);
            }
        
        // repeated lines ======================================================
        outputFile = File.createTempFile(...);
        try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
                workbook.write(outputStream);
            } catch (IOException e) {
                LoggingUtils.error("Writing failed ", e);
            }
            final FileInputStream input = new FileInputStream(outputFile);

            final String fileName = TextBundleUtil.read(...);
            return new MockMultipartFile(fileName,
                    fileName, CONTENT_TYPE, IOUtils.toByteArray(input));
            //
        }
    }

At the end, this pattern needs to be used with care because you need to factorize all that you can to make the builder really useful, but not too much to make it a "boat of anything".最后,这个模式需要小心使用,因为你需要分解所有你能做的使构建器真正有用的因素,但不要太多以使其成为“任何东西的船”。 For instance, you can have as input the sheet path or an inputstream of it to make it more useful/generic.例如,您可以将工作表路径或其输入流作为输入,以使其更有用/通用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM