Decorator in Java

23,188

Solution 1

If you are particularly interested in doing this kind of stuff with annotations (you don't have to really):

This example should get you started:

public class AnnotationTest
{
    @Target( ElementType.METHOD )
    @Retention( RetentionPolicy.RUNTIME )
    public static @interface TagWrapper
    {
        public String[] value() default {};
    }

    public static interface TextFragment
    {
        public String getText();
    }

    public static class TagWrapperProcessor
    {
        public static String getWrapperTextFragment( TextFragment fragment )
        {
            try
            {
                Method getText = fragment.getClass().getMethod( "getText" );
                TagWrapper tagWrapper = getText.getAnnotation( TagWrapper.class );
                String formatString = "<%s>%s</%s>";
                String result = ( String ) getText.invoke( fragment );
                for ( String tag : tagWrapper.value() )
                {
                    result = String.format( formatString, tag, result, tag );
                }
                return result;
            }
            catch ( Exception e )
            {
                throw new RuntimeException( e );
            }
        }
    }

    public static class BoldItalicFragment implements TextFragment
    {

        private String _text;

        public BoldItalicFragment( String text )
        {
            _text = text;
        }

        @Override
        @TagWrapper(
        {
            "b", "i"
        } )
        public String getText()
        {
            return _text;
        }

    }

    @Test
    public void testStuff()
    {
        System.out.println( TagWrapperProcessor.getWrapperTextFragment( new BoldItalicFragment( "Hello, World!" ) ) ); // prints: <i><b>Hello, World!</b></i>
    }
}

Solution 2

This is late but I think it may help the other people. From Java 8 with Function interface, we can write something close to python decorator like this:

Function<Function<String, String>, Function<String, String>> makebold = func -> input -> "<b>" + func.apply(input) + "</b>";
Function<Function<String, String>, Function<String, String>> makeitalic = func -> input -> "<i>" + func.apply(input) + "</i>";

Function<String, String> helloWorld = input -> "hello world";
        System.out.println(makebold.apply(makeitalic.apply(helloWorld)).apply("")); // <b><i>hello world</i></b>

Solution 3

1) The link you cited is a good one - it does justice to the "Decorator Pattern" with respect to Java. "Design Patterns" themselves, of course, are independent of any particular OO language:

2) Here is another good link:

In Java, a classical example of the decorator pattern is the Java I/O Streams implementation.

FileReader       frdr = new FileReader(filename);
LineNumberReader lrdr = new LineNumberReader(frdr);

4) So yes, the "decorator pattern" is a good candidate for this problem.

Personally, I would prefer this kind of solution:

   String myHtml = 
     new BoldText (
       new ItalicText (
         new HtmlText ("See spot run")));

5) However annotations are also an option. For example:

Share:
23,188
Crazenezz
Author by

Crazenezz

Updated on January 23, 2021

Comments

  • Crazenezz
    Crazenezz over 3 years

    I see about decorator example in Python:

    def makebold(fn):
        def wrapped():
            return "<b>" + fn() + "</b>"
        return wrapped
    
    def makeitalic(fn):
        def wrapped():
            return "<i>" + fn() + "</i>"
        return wrapped
    
    @makebold
    @makeitalic
    def hello():
        return "hello world"
    
    print hello() ## returns <b><i>hello world</i></b>
    

    And got some curious how it can be implement in Java, so I search and got some example using Decorator Design Pattern.

    public class Main {
    
        public static void main(String[] args) {
            Wrapper word = new BoldWrapper(new ItalicWrapper());
            // display <b><i>hello world</i></b>
            System.out.println(word.make("Hello World"));
        }
    }
    
    public interface Wrapper {
    
        public String make(String str);
    
    }
    
    public class BoldWrapper implements Wrapper {
    
        private Wrapper wrapper;
    
        public BoldWrapper() {
    
        }
    
        public BoldWrapper(Wrapper wrapper) {
            this.wrapper = wrapper;
        }
    
        @Override
        public String make(String str) {
            if(wrapper != null) {
                str = wrapper.make(str);
            }
    
            return "<b>" + str + "</b>";
        }
    
    }
    
    public class ItalicWrapper implements Wrapper {
    
        private Wrapper wrapper;
    
        public ItalicWrapper() {
    
        }
    
        public ItalicWrapper(Wrapper wrapper) {
            this.wrapper = wrapper;
        }
    
        @Override
        public String make(String str) {
            if(wrapper != null) {
                str = wrapper.make(str);
            }
    
            return "<i>" + str + "</i>";
        }
    
    }
    

    How do I make this like the Python example above using a Java Annotation like this one:

    public class Main {
        public static void main(String[] args) {
            @BoldWrapper
            @ItalicWrapper
            String str = "Hello World";
            // Display <b><i>Hello World</i></b>
        }
    }
    
    public @interface BoldWrapper {
        public void wrap() default "<b>" + str + "</b>";
    }
    
    public @interface ItalicWrapper {
        public void wrap() default "<i>" + str + "</i>";
    }
    

    I got some problem when I tried to make the sample, the problem is I don't know how I can pass the str value from the main method to the BoldWrapper and ItalicWrapper so it can concatenate and how to return it, so the main method can display the result that has been concatenate.

    Please advise if there is something wrong with my understanding of annotation.

  • Crazenezz
    Crazenezz about 10 years
    Thank you so much for the information, using the Builder Pattern is the key to solve the problem. But still I want to research more if possible to using Annotation to solve the problem. And I also aware that using annotation has side effect for the memory.