What is the “Execute Around” idiom?

后端 未结 8 1143
不思量自难忘°
不思量自难忘° 2020-11-22 12:39

What is this \"Execute Around\" idiom (or similar) I\'ve been hearing about? Why might I use it, and why might I not want to use it?

相关标签:
8条回答
  • 2020-11-22 13:30

    Basically it's the pattern where you write a method to do things which are always required, e.g. resource allocation and clean-up, and make the caller pass in "what we want to do with the resource". For example:

    public interface InputStreamAction
    {
        void useStream(InputStream stream) throws IOException;
    }
    
    // Somewhere else    
    
    public void executeWithFile(String filename, InputStreamAction action)
        throws IOException
    {
        InputStream stream = new FileInputStream(filename);
        try {
            action.useStream(stream);
        } finally {
            stream.close();
        }
    }
    
    // Calling it
    executeWithFile("filename.txt", new InputStreamAction()
    {
        public void useStream(InputStream stream) throws IOException
        {
            // Code to use the stream goes here
        }
    });
    
    // Calling it with Java 8 Lambda Expression:
    executeWithFile("filename.txt", s -> System.out.println(s.read()));
    
    // Or with Java 8 Method reference:
    executeWithFile("filename.txt", ClassName::methodName);
    

    The calling code doesn't need to worry about the open/clean-up side - it will be taken care of by executeWithFile.

    This was frankly painful in Java because closures were so wordy, starting with Java 8 lambda expressions can be implemented like in many other languages (e.g. C# lambda expressions, or Groovy), and this special case is handled since Java 7 with try-with-resources and AutoClosable streams.

    Although "allocate and clean-up" is the typical example given, there are plenty of other possible examples - transaction handling, logging, executing some code with more privileges etc. It's basically a bit like the template method pattern but without inheritance.

    0 讨论(0)
  • 2020-11-22 13:33

    I see you have a Java tag here so I'll use Java as an example even though the pattern isn't platform-specific.

    The idea is that sometimes you have code that always involves the same boilerplate before you run the code and after you run the code. A good example is JDBC. You always grab a connection and create a statement (or prepared statement) before running the actual query and processing the result set, and then you always do the same boilerplate cleanup at the end--closing the statement and connection.

    The idea with execute-around is that it's better if you can factor out the boilerplate code. That saves you some typing, but the reason is deeper. It's the don't-repeat-yourself (DRY) principle here--you isolate the code to one location so if there's a bug or you need to change it, or you just want to understand it, it's all in one place.

    The thing that's a little tricky with this kind of factoring-out though is that you have references that both the "before" and "after" parts need to see. In the JDBC example this would include the Connection and (Prepared)Statement. So to handle that you essentially "wrap" your target code with the boilerplate code.

    You may be familiar with some common cases in Java. One is servlet filters. Another is AOP around advice. A third is the various xxxTemplate classes in Spring. In each case you have some wrapper object into which your "interesting" code (say the JDBC query and result set processing) is injected. The wrapper object does the "before" part, invokes the interesting code and then does the "after" part.

    0 讨论(0)
提交回复
热议问题